From b0b77b3047356b2bd507d55ccd3a661b54d5a150 Mon Sep 17 00:00:00 2001 From: TolyaTalamanov Date: Sun, 2 Oct 2022 20:54:08 +0000 Subject: [PATCH 1/3] Add cfgOutputPrecision --- .../gapi/include/opencv2/gapi/infer/ie.hpp | 51 ++++++++- .../gapi/samples/pipeline_modeling_tool.cpp | 6 + .../pipeline_builder.hpp | 4 + modules/gapi/src/backends/ie/giebackend.cpp | 49 +++++++- .../gapi/test/infer/gapi_infer_ie_test.cpp | 105 ++++++++++++++++++ 5 files changed, 212 insertions(+), 3 deletions(-) diff --git a/modules/gapi/include/opencv2/gapi/infer/ie.hpp b/modules/gapi/include/opencv2/gapi/infer/ie.hpp index 204bd8f266..1e8fbc576c 100644 --- a/modules/gapi/include/opencv2/gapi/infer/ie.hpp +++ b/modules/gapi/include/opencv2/gapi/infer/ie.hpp @@ -88,6 +88,15 @@ struct ParamDesc { cv::optional vpl_preproc_device; cv::optional vpl_preproc_ctx; + + using precision_t = int; + using precision_map_t = std::unordered_map; + // NB: cv::util::monostate is default value that means precision wasn't specified. + using precision_variant_t = cv::util::variant; + precision_variant_t output_precision; + }; } // namespace detail @@ -132,6 +141,7 @@ public: , {} , {} , {} + , {} , {}} { }; @@ -156,6 +166,7 @@ public: , {} , {} , {} + , {} , {}} { }; @@ -351,6 +362,29 @@ public: return *this; } + /** @brief Specifies the output precision for model. + + The function is used to set an output precision for model. + + @param precision Precision in OpenCV format. + @return reference to this parameter structure. + */ + Params& cfgOutputPrecision(detail::ParamDesc::precision_t precision) { + desc.output_precision = precision; + return *this; + } + + /** @overload + + @param precision_map Map of pairs: name of corresponding output layer and its precision + @return reference to this parameter structure. + */ + Params& + cfgOutputPrecision(detail::ParamDesc::precision_map_t precision_map) { + desc.output_precision = precision_map; + return *this; + } + // BEGIN(G-API's network parametrization API) GBackend backend() const { return cv::gapi::ie::backend(); } std::string tag() const { return Net::tag(); } @@ -385,7 +419,7 @@ public: const std::string &device) : desc{ model, weights, device, {}, {}, {}, 0u, 0u, detail::ParamDesc::Kind::Load, true, {}, {}, {}, 1u, - {}, {}, {}, {}}, + {}, {}, {}, {}, {}}, m_tag(tag) { }; @@ -403,7 +437,7 @@ public: const std::string &device) : desc{ model, {}, device, {}, {}, {}, 0u, 0u, detail::ParamDesc::Kind::Import, true, {}, {}, {}, 1u, - {}, {}, {}, {}}, + {}, {}, {}, {}, {}}, m_tag(tag) { }; @@ -476,6 +510,19 @@ public: return *this; } + /** @see ie::Params::cfgOutputPrecision */ + Params& cfgOutputPrecision(detail::ParamDesc::precision_t precision) { + desc.output_precision = precision; + return *this; + } + + /** @overload */ + Params& + cfgOutputPrecision(detail::ParamDesc::precision_map_t precision_map) { + desc.output_precision = precision_map; + return *this; + } + // BEGIN(G-API's network parametrization API) GBackend backend() const { return cv::gapi::ie::backend(); } std::string tag() const { return m_tag; } diff --git a/modules/gapi/samples/pipeline_modeling_tool.cpp b/modules/gapi/samples/pipeline_modeling_tool.cpp index 60547a9c9b..540c8d7766 100644 --- a/modules/gapi/samples/pipeline_modeling_tool.cpp +++ b/modules/gapi/samples/pipeline_modeling_tool.cpp @@ -210,6 +210,12 @@ InferParams read(const cv::FileNode& fn) { params.input_layers = readList(fn, "input_layers", name); params.output_layers = readList(fn, "output_layers", name); params.config = readMap(fn["config"]); + + auto out_prec_str = readOpt(fn["output_precision"]); + if (out_prec_str.has_value()) { + params.out_precision = + cv::optional(strToPrecision(out_prec_str.value())); + } return params; } diff --git a/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp b/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp index a3f187249d..411a5b2e6d 100644 --- a/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp +++ b/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp @@ -258,6 +258,7 @@ struct InferParams { std::vector input_layers; std::vector output_layers; std::map config; + cv::util::optional out_precision; }; class PipelineBuilder { @@ -362,6 +363,9 @@ void PipelineBuilder::addInfer(const CallParams& call_params, } pp->pluginConfig(infer_params.config); + if (infer_params.out_precision) { + pp->cfgOutputPrecision(infer_params.out_precision.value()); + } m_state->networks += cv::gapi::networks(*pp); addCall(call_params, diff --git a/modules/gapi/src/backends/ie/giebackend.cpp b/modules/gapi/src/backends/ie/giebackend.cpp index eca07ce9df..b76a468496 100644 --- a/modules/gapi/src/backends/ie/giebackend.cpp +++ b/modules/gapi/src/backends/ie/giebackend.cpp @@ -197,6 +197,16 @@ inline IE::Blob::Ptr wrapIE(const cv::MediaFrame::View& view, template inline void copyFromIE(const IE::Blob::Ptr &blob, MatType &mat) { + const auto& desc = blob->getTensorDesc(); + const auto ie_type = toCV(desc.getPrecision()); + if (ie_type != mat.type()) { + std::stringstream ss; + ss << "Failed while copying blob from IE to OCV: " + << "Blobs have different data types.\n" + << "IE type: " << ie_type << "\n" + << "OCV type: " << mat.type() << std::endl; + throw std::logic_error(ss.str()); + } switch (blob->getTensorDesc().getPrecision()) { #define HANDLE(E,T) \ case IE::Precision::E: std::copy_n(blob->buffer().as(), \ @@ -365,6 +375,13 @@ struct IEUnit { cv::util::throw_error(std::logic_error("Unsupported ParamDesc::Kind")); } + if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import && + !cv::util::holds_alternative(params.output_precision)) { + cv::util::throw_error( + std::logic_error("Setting output precision isn't supported for imported network")); + } + + using namespace cv::gapi::wip::onevpl; if (params.vpl_preproc_device.has_value() && params.vpl_preproc_ctx.has_value()) { using namespace cv::gapi::wip; @@ -1122,6 +1139,32 @@ static IE::PreProcessInfo configurePreProcInfo(const IE::InputInfo::CPtr& ii, return info; } +using namespace cv::gapi::ie::detail; +static void configureOutputPrecision(const IE::OutputsDataMap &outputs_info, + const ParamDesc::precision_variant_t &output_precision) { + switch (output_precision.index()) { + case ParamDesc::precision_variant_t::index_of(): { + auto precision = toIE(cv::util::get(output_precision)); + for (auto it : outputs_info) { + it.second->setPrecision(precision); + } + break; + } + case ParamDesc::precision_variant_t::index_of(): { + const auto& precision_map = + cv::util::get(output_precision); + for (auto it : precision_map) { + outputs_info.at(it.first)->setPrecision(toIE(it.second)); + } + break; + } + case ParamDesc::precision_variant_t::index_of(): { + // Do nothing; + break; + } + } +} + // NB: This is a callback used by async infer // to post outputs blobs (cv::GMat's). static void PostOutputs(InferenceEngine::InferRequest &request, @@ -1241,7 +1284,7 @@ struct Infer: public cv::detail::KernelTag { GAPI_Assert(uu.params.input_names.size() == in_metas.size() && "Known input layers count doesn't match input meta count"); - // NB: Configuring input precision and network reshape must be done + // NB: Configuring input/output precision and network reshape must be done // only in the loadNetwork case. using namespace cv::gapi::ie::detail; if (uu.params.kind == ParamDesc::Kind::Load) { @@ -1275,6 +1318,7 @@ struct Infer: public cv::detail::KernelTag { if (!input_reshape_table.empty()) { const_cast(&uu.net)->reshape(input_reshape_table); } + configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision); } else { GAPI_Assert(uu.params.kind == ParamDesc::Kind::Import); auto inputs = uu.this_network.GetInputsInfo(); @@ -1393,6 +1437,7 @@ struct InferROI: public cv::detail::KernelTag { const_cast(uu.net_input_params) .set_param(input_name, ii->getTensorDesc()); } + configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision); } else { GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); auto inputs = uu.this_network.GetInputsInfo(); @@ -1513,6 +1558,7 @@ struct InferList: public cv::detail::KernelTag { if (!input_reshape_table.empty()) { const_cast(&uu.net)->reshape(input_reshape_table); } + configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision); } else { GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); std::size_t idx = 1u; @@ -1667,6 +1713,7 @@ struct InferList2: public cv::detail::KernelTag { if (!input_reshape_table.empty()) { const_cast(&uu.net)->reshape(input_reshape_table); } + configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision); } else { GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); auto inputs = uu.this_network.GetInputsInfo(); diff --git a/modules/gapi/test/infer/gapi_infer_ie_test.cpp b/modules/gapi/test/infer/gapi_infer_ie_test.cpp index 3741438373..54c67c02d0 100644 --- a/modules/gapi/test/infer/gapi_infer_ie_test.cpp +++ b/modules/gapi/test/infer/gapi_infer_ie_test.cpp @@ -2956,6 +2956,111 @@ TEST(TestAgeGender, ThrowBlobAndInputPrecisionMismatchStreaming) } } +TEST(TestAgeGenderIE, ChangeOutputPrecision) +{ + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml"); + params.weights_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin"); + params.device_id = "CPU"; + + cv::Mat in_mat(cv::Size(320, 240), CV_8UC3); + cv::randu(in_mat, 0, 255); + + cv::Mat gapi_age, gapi_gender; + + // Load & run IE network + IE::Blob::Ptr ie_age, ie_gender; + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto net = cv::gimpl::ie::wrap::readNetwork(params); + setNetParameters(net); + for (auto it : net.getOutputsInfo()) { + it.second->setPrecision(IE::Precision::U8); + } + auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params); + auto infer_request = this_network.CreateInferRequest(); + infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat)); + infer_request.Infer(); + ie_age = infer_request.GetBlob("age_conv3"); + ie_gender = infer_request.GetBlob("prob"); + } + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GMat in; + cv::GMat age, gender; + std::tie(age, gender) = cv::gapi::infer(in); + cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.weights_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }) + .cfgOutputPrecision(CV_8U); + comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" ); + normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output"); +} + +TEST(TestAgeGenderIE, ChangeSpecificOutputPrecison) +{ + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml"); + params.weights_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin"); + params.device_id = "CPU"; + + cv::Mat in_mat(cv::Size(320, 240), CV_8UC3); + cv::randu(in_mat, 0, 255); + + cv::Mat gapi_age, gapi_gender; + + // Load & run IE network + IE::Blob::Ptr ie_age, ie_gender; + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto net = cv::gimpl::ie::wrap::readNetwork(params); + setNetParameters(net); + + // NB: Specify precision only for "prob" output. + net.getOutputsInfo().at("prob")->setPrecision(IE::Precision::U8); + + auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params); + auto infer_request = this_network.CreateInferRequest(); + infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat)); + infer_request.Infer(); + ie_age = infer_request.GetBlob("age_conv3"); + ie_gender = infer_request.GetBlob("prob"); + } + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GMat in; + cv::GMat age, gender; + std::tie(age, gender) = cv::gapi::infer(in); + cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.weights_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }) + .cfgOutputPrecision({{"prob", CV_8U}}); + comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" ); + normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output"); +} + } // namespace opencv_test #endif // HAVE_INF_ENGINE From a6fbd8287c325bbcd3f49f52e5b7f83f9b1d73ab Mon Sep 17 00:00:00 2001 From: TolyaTalamanov Date: Mon, 3 Oct 2022 08:04:15 +0000 Subject: [PATCH 2/3] Fix comments to review --- .../gapi/include/opencv2/gapi/infer/ie.hpp | 32 ++++++++----- modules/gapi/src/backends/ie/giebackend.cpp | 48 +++++++++---------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/modules/gapi/include/opencv2/gapi/infer/ie.hpp b/modules/gapi/include/opencv2/gapi/infer/ie.hpp index 1e8fbc576c..d74cf77acd 100644 --- a/modules/gapi/include/opencv2/gapi/infer/ie.hpp +++ b/modules/gapi/include/opencv2/gapi/infer/ie.hpp @@ -89,13 +89,17 @@ struct ParamDesc { cv::optional vpl_preproc_device; cv::optional vpl_preproc_ctx; - using precision_t = int; - using precision_map_t = std::unordered_map; - // NB: cv::util::monostate is default value that means precision wasn't specified. - using precision_variant_t = cv::util::variant; - precision_variant_t output_precision; + using PrecisionT = int; + using PrecisionMapT = std::unordered_map; + // NB: This parameter can contain: + // 1. cv::util::monostate - Don't specify precision, but use default from IR/Blob. + // 2. PrecisionT (CV_8U, CV_32F, ...) - Specifies precision for all output layers. + // 3. PrecisionMapT ({{"layer0", CV_32F}, {"layer1", CV_16F}} - Specifies precision for certain output layer. + // cv::util::monostate is default value that means precision wasn't specified. + using PrecisionVariantT = cv::util::variant; + PrecisionVariantT output_precision; }; } // namespace detail @@ -366,21 +370,23 @@ public: The function is used to set an output precision for model. - @param precision Precision in OpenCV format. + @param precision Precision in OpenCV format (CV_8U, CV_32F, ...) + will be applied to all output layers. @return reference to this parameter structure. */ - Params& cfgOutputPrecision(detail::ParamDesc::precision_t precision) { + Params& cfgOutputPrecision(detail::ParamDesc::PrecisionT precision) { desc.output_precision = precision; return *this; } /** @overload - @param precision_map Map of pairs: name of corresponding output layer and its precision + @param precision_map Map of pairs: name of corresponding output layer + and its precision in OpenCV format (CV_8U, CV_32F, ...) @return reference to this parameter structure. */ Params& - cfgOutputPrecision(detail::ParamDesc::precision_map_t precision_map) { + cfgOutputPrecision(detail::ParamDesc::PrecisionMapT precision_map) { desc.output_precision = precision_map; return *this; } @@ -511,14 +517,14 @@ public: } /** @see ie::Params::cfgOutputPrecision */ - Params& cfgOutputPrecision(detail::ParamDesc::precision_t precision) { + Params& cfgOutputPrecision(detail::ParamDesc::PrecisionT precision) { desc.output_precision = precision; return *this; } /** @overload */ Params& - cfgOutputPrecision(detail::ParamDesc::precision_map_t precision_map) { + cfgOutputPrecision(detail::ParamDesc::PrecisionMapT precision_map) { desc.output_precision = precision_map; return *this; } diff --git a/modules/gapi/src/backends/ie/giebackend.cpp b/modules/gapi/src/backends/ie/giebackend.cpp index b76a468496..6c95b860a9 100644 --- a/modules/gapi/src/backends/ie/giebackend.cpp +++ b/modules/gapi/src/backends/ie/giebackend.cpp @@ -201,10 +201,10 @@ inline void copyFromIE(const IE::Blob::Ptr &blob, MatType &mat) { const auto ie_type = toCV(desc.getPrecision()); if (ie_type != mat.type()) { std::stringstream ss; - ss << "Failed while copying blob from IE to OCV: " - << "Blobs have different data types.\n" - << "IE type: " << ie_type << "\n" - << "OCV type: " << mat.type() << std::endl; + ss << "Failed to copy blob from IE to OCV: " + << "Blobs have different data types " + << "(IE type: " << ie_type + << " vs OCV type: " << mat.type() << ")." << std::endl; throw std::logic_error(ss.str()); } switch (blob->getTensorDesc().getPrecision()) { @@ -1140,29 +1140,25 @@ static IE::PreProcessInfo configurePreProcInfo(const IE::InputInfo::CPtr& ii, } using namespace cv::gapi::ie::detail; -static void configureOutputPrecision(const IE::OutputsDataMap &outputs_info, - const ParamDesc::precision_variant_t &output_precision) { - switch (output_precision.index()) { - case ParamDesc::precision_variant_t::index_of(): { - auto precision = toIE(cv::util::get(output_precision)); - for (auto it : outputs_info) { - it.second->setPrecision(precision); +static void configureOutputPrecision(const IE::OutputsDataMap &outputs_info, + const ParamDesc::PrecisionVariantT &output_precision) { + cv::util::visit(cv::util::overload_lambdas( + [&outputs_info](ParamDesc::PrecisionT cvdepth) { + auto precision = toIE(cvdepth); + for (auto it : outputs_info) { + it.second->setPrecision(precision); + } + }, + [&outputs_info](const ParamDesc::PrecisionMapT& precision_map) { + for (auto it : precision_map) { + outputs_info.at(it.first)->setPrecision(toIE(it.second)); + } + }, + [&outputs_info](cv::util::monostate) { + // Do nothing. } - break; - } - case ParamDesc::precision_variant_t::index_of(): { - const auto& precision_map = - cv::util::get(output_precision); - for (auto it : precision_map) { - outputs_info.at(it.first)->setPrecision(toIE(it.second)); - } - break; - } - case ParamDesc::precision_variant_t::index_of(): { - // Do nothing; - break; - } - } + ), output_precision + ); } // NB: This is a callback used by async infer From b1d28d5b4a6807d10f44a52c0300843266610236 Mon Sep 17 00:00:00 2001 From: TolyaTalamanov Date: Mon, 3 Oct 2022 09:04:49 +0000 Subject: [PATCH 3/3] Expand performance report --- .../pipeline_modeling_tool/dummy_source.hpp | 1 + .../pipeline_modeling_tool/pipeline.hpp | 91 +++++++++++-------- .../pipeline_builder.hpp | 16 ++-- .../samples/pipeline_modeling_tool/utils.hpp | 15 +++ 4 files changed, 76 insertions(+), 47 deletions(-) diff --git a/modules/gapi/samples/pipeline_modeling_tool/dummy_source.hpp b/modules/gapi/samples/pipeline_modeling_tool/dummy_source.hpp index d77e120081..4c2ea1638c 100644 --- a/modules/gapi/samples/pipeline_modeling_tool/dummy_source.hpp +++ b/modules/gapi/samples/pipeline_modeling_tool/dummy_source.hpp @@ -18,6 +18,7 @@ public: const bool drop_frames); bool pull(cv::gapi::wip::Data& data) override; cv::GMetaArg descr_of() const override; + double latency() const { return m_latency; }; private: double m_latency; diff --git a/modules/gapi/samples/pipeline_modeling_tool/pipeline.hpp b/modules/gapi/samples/pipeline_modeling_tool/pipeline.hpp index 2951d45610..91107c6dad 100644 --- a/modules/gapi/samples/pipeline_modeling_tool/pipeline.hpp +++ b/modules/gapi/samples/pipeline_modeling_tool/pipeline.hpp @@ -1,13 +1,18 @@ #ifndef OPENCV_GAPI_PIPELINE_MODELING_TOOL_PIPELINE_HPP #define OPENCV_GAPI_PIPELINE_MODELING_TOOL_PIPELINE_HPP +#include + struct PerfReport { - std::string name; - double avg_latency = 0.0; - double throughput = 0.0; - int64_t first_run_latency = 0; - int64_t elapsed = 0; - int64_t compilation_time = 0; + std::string name; + double avg_latency = 0.0; + int64_t min_latency = 0; + int64_t max_latency = 0; + int64_t first_latency = 0; + double throughput = 0.0; + int64_t elapsed = 0; + int64_t warmup_time = 0; + int64_t num_late_frames = 0; std::vector latencies; std::string toStr(bool expanded = false) const; @@ -15,17 +20,19 @@ struct PerfReport { std::string PerfReport::toStr(bool expand) const { std::stringstream ss; - ss << name << ": Compilation time: " << compilation_time << " ms; " - << "Average latency: " << avg_latency << " ms; Throughput: " - << throughput << " FPS; First latency: " - << first_run_latency << " ms"; - + ss << name << ": \n" + << " Warm up time: " << warmup_time << " ms\n" + << " Execution time: " << elapsed << " ms\n" + << " Frames: " << num_late_frames << "/" << latencies.size() << " (late/all)\n" + << " Latency:\n" + << " first: " << first_latency << " ms\n" + << " min: " << min_latency << " ms\n" + << " max: " << max_latency << " ms\n" + << " avg: " << std::fixed << std::setprecision(3) << avg_latency << " ms\n" + << " Throughput: " << std::fixed << std::setprecision(3) << throughput << " FPS"; if (expand) { - ss << "\nTotal processed frames: " << latencies.size() - << "\nTotal elapsed time: " << elapsed << " ms" << std::endl; for (size_t i = 0; i < latencies.size(); ++i) { - ss << std::endl; - ss << "Frame:" << i << "\nLatency: " + ss << "\nFrame:" << i << "\nLatency: " << latencies[i] << " ms"; } } @@ -37,11 +44,11 @@ class Pipeline { public: using Ptr = std::shared_ptr; - Pipeline(std::string&& name, - cv::GComputation&& comp, - cv::gapi::wip::IStreamSource::Ptr&& src, - cv::GCompileArgs&& args, - const size_t num_outputs); + Pipeline(std::string&& name, + cv::GComputation&& comp, + std::shared_ptr&& src, + cv::GCompileArgs&& args, + const size_t num_outputs); void compile(); void run(double work_time_ms); @@ -59,19 +66,19 @@ protected: virtual void _compile() = 0; virtual RunPerf _run(double work_time_ms) = 0; - std::string m_name; - cv::GComputation m_comp; - cv::gapi::wip::IStreamSource::Ptr m_src; - cv::GCompileArgs m_args; - size_t m_num_outputs; - PerfReport m_perf; + std::string m_name; + cv::GComputation m_comp; + std::shared_ptr m_src; + cv::GCompileArgs m_args; + size_t m_num_outputs; + PerfReport m_perf; }; -Pipeline::Pipeline(std::string&& name, - cv::GComputation&& comp, - cv::gapi::wip::IStreamSource::Ptr&& src, - cv::GCompileArgs&& args, - const size_t num_outputs) +Pipeline::Pipeline(std::string&& name, + cv::GComputation&& comp, + std::shared_ptr&& src, + cv::GCompileArgs&& args, + const size_t num_outputs) : m_name(std::move(name)), m_comp(std::move(comp)), m_src(std::move(src)), @@ -81,7 +88,7 @@ Pipeline::Pipeline(std::string&& name, } void Pipeline::compile() { - m_perf.compilation_time = + m_perf.warmup_time = utils::measure([this]() { _compile(); }); @@ -90,17 +97,23 @@ void Pipeline::compile() { void Pipeline::run(double work_time_ms) { auto run_perf = _run(work_time_ms); - m_perf.elapsed = run_perf.elapsed; - m_perf.latencies = std::move(run_perf.latencies); + m_perf.elapsed = run_perf.elapsed; + m_perf.latencies = std::move(run_perf.latencies); + m_perf.avg_latency = utils::avg(m_perf.latencies); + m_perf.min_latency = utils::min(m_perf.latencies); + m_perf.max_latency = utils::max(m_perf.latencies); + m_perf.first_latency = m_perf.latencies[0]; + + // NB: Count how many executions don't fit into camera latency interval. + m_perf.num_late_frames = + std::count_if(m_perf.latencies.begin(), m_perf.latencies.end(), + [this](int64_t latency) { + return static_cast(latency) > m_src->latency(); + }); - m_perf.avg_latency = - std::accumulate(m_perf.latencies.begin(), - m_perf.latencies.end(), - 0.0) / static_cast(m_perf.latencies.size()); m_perf.throughput = (m_perf.latencies.size() / static_cast(m_perf.elapsed)) * 1000; - m_perf.first_run_latency = m_perf.latencies[0]; } const PerfReport& Pipeline::report() const { diff --git a/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp b/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp index a3f187249d..cad8aa651a 100644 --- a/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp +++ b/modules/gapi/samples/pipeline_modeling_tool/pipeline_builder.hpp @@ -295,15 +295,15 @@ private: std::vector output_edges; }; - M calls_map; - std::vector all_calls; + M calls_map; + std::vector all_calls; - cv::gapi::GNetPackage networks; - cv::gapi::GKernelPackage kernels; - cv::GCompileArgs compile_args; - cv::gapi::wip::IStreamSource::Ptr src; - PLMode mode = PLMode::STREAMING; - std::string name; + cv::gapi::GNetPackage networks; + cv::gapi::GKernelPackage kernels; + cv::GCompileArgs compile_args; + std::shared_ptr src; + PLMode mode = PLMode::STREAMING; + std::string name; }; std::unique_ptr m_state; diff --git a/modules/gapi/samples/pipeline_modeling_tool/utils.hpp b/modules/gapi/samples/pipeline_modeling_tool/utils.hpp index a5be323747..6eb6bb7202 100644 --- a/modules/gapi/samples/pipeline_modeling_tool/utils.hpp +++ b/modules/gapi/samples/pipeline_modeling_tool/utils.hpp @@ -104,6 +104,21 @@ void mergeMapWith(std::map& target, const std::map& second) { } } +template +double avg(const std::vector& vec) { + return std::accumulate(vec.begin(), vec.end(), 0.0) / vec.size(); +} + +template +T max(const std::vector& vec) { + return *std::max_element(vec.begin(), vec.end()); +} + +template +T min(const std::vector& vec) { + return *std::min_element(vec.begin(), vec.end()); +} + } // namespace utils #endif // OPENCV_GAPI_PIPELINE_MODELING_TOOL_UTILS_HPP