Introduce WA to improve performance of find_port() method (#20573)

* Introduce WA to improve performance of find_port() method

* Add mutex

* Remove redindant lock

* Reduce the number of get_tensor_ptr calls

* Fixed typo

* Removed WAs from Hetero plugin
This commit is contained in:
Ilya Churaev authored and GitHub committed 2023-10-23 13:44:58 +04:00
1 parent 6e4ec88db8
commit 865b21ecd4
3 files changed
+51 -35

No files matched your search

@@ -124,6 +124,12 @@ protected:
}
};
/**
* @brief Finds input or output port
* @return structure which contains index of Input/Output or report that port wasn't found
*/
FoundPort find_port(const ov::Output<const ov::Node>& port) const;
/**
* @brief Converts batched tensors to tensor
*/
@@ -157,12 +163,9 @@ private:
std::shared_ptr<const ov::ICompiledModel> m_compiled_model;
// Mutable to return reference to ov::Tensor
mutable std::unordered_map<std::shared_ptr<ov::descriptor::Tensor>, ov::SoPtr<ov::ITensor>> m_tensors;
/**
* @brief Finds input or output port
* @return structure which contains index of Input/Output or report that port wasn't found
*/
FoundPort find_port(const ov::Output<const ov::Node>& port) const;
// Cache ports
mutable std::unordered_map<size_t, FoundPort> m_cached_ports;
mutable std::mutex m_cache_mutex;
};
}; // namespace ov
+34 -16
View File
@@ -4,6 +4,7 @@
#include "openvino/runtime/isync_infer_request.hpp"
#include <functional>
#include <memory>
#include <unordered_map>
@@ -17,6 +18,7 @@
#include "openvino/runtime/make_tensor.hpp"
#include "openvino/runtime/plugin_itt.hpp"
#include "openvino/runtime/tensor.hpp"
#include "openvino/util/common_util.hpp"
namespace {
void check_batched_tensors(const ov::Output<const ov::Node>& input,
@@ -93,14 +95,18 @@ ov::IInferRequest::~IInferRequest() = default;
ov::ISyncInferRequest::ISyncInferRequest(const std::shared_ptr<const ov::ICompiledModel>& compiled_model)
: m_compiled_model(compiled_model) {
OPENVINO_ASSERT(m_compiled_model);
// Create map of empty tensors
for (const auto& input : get_inputs()) {
if (m_tensors.find(input.get_tensor_ptr()) == m_tensors.end())
m_tensors[input.get_tensor_ptr()] = ov::SoPtr<ov::ITensor>();
}
for (const auto& output : get_outputs()) {
if (m_tensors.find(output.get_tensor_ptr()) == m_tensors.end())
m_tensors[output.get_tensor_ptr()] = ov::SoPtr<ov::ITensor>();
// Create map of empty tensors and cache ports from the compiled model
auto port_type = ov::ISyncInferRequest::FoundPort::Type::INPUT;
for (const auto& ports : {get_inputs(), get_outputs()}) {
for (size_t i = 0; i < ports.size(); i++) {
const auto& port = ports[i];
if (m_tensors.find(port.get_tensor_ptr()) == m_tensors.end())
m_tensors[port.get_tensor_ptr()] = ov::SoPtr<ov::ITensor>();
size_t port_hash = ov::util::hash_combine(std::vector<size_t>{std::hash<const ov::Node*>()(port.get_node()),
std::hash<size_t>()(port.get_index())});
m_cached_ports[port_hash] = {i, port_type};
}
port_type = ov::ISyncInferRequest::FoundPort::Type::OUTPUT;
}
}
@@ -118,18 +124,30 @@ ov::ISyncInferRequest::FoundPort ov::ISyncInferRequest::find_port(const ov::Outp
// This function is hotspot, need optimization.
auto check_nodes = [](const ov::Node* node1, const ov::Node* node2) {
return node1 == node2 ||
(node1->get_friendly_name() == node2->get_friendly_name() &&
node1->get_type_info() == node2->get_type_info() &&
node1->outputs().size() == node2->outputs().size() && node1->inputs().size() == node2->inputs().size());
(node1->outputs().size() == node2->outputs().size() &&
node1->inputs().size() == node2->inputs().size() && node1->get_type_info() == node2->get_type_info() &&
node1->get_friendly_name() == node2->get_friendly_name());
};
// Find port without caching work slow because we need each time iterate over all ports and compare different
// strings So use WA with caching in order to make 2+ calls for the same ports faster.
// Calculate hash for the port
size_t port_hash = ov::util::hash_combine(
std::vector<size_t>{std::hash<const ov::Node*>()(port.get_node()), std::hash<size_t>()(port.get_index())});
{
std::lock_guard<std::mutex> lock(m_cache_mutex);
if (m_cached_ports.find(port_hash) != m_cached_ports.end()) {
// Cached port for the hash was found
return m_cached_ports[port_hash];
}
}
ov::ISyncInferRequest::FoundPort::Type type = ov::ISyncInferRequest::FoundPort::Type::INPUT;
for (const auto& ports : {get_inputs(), get_outputs()}) {
for (size_t i = 0; i < ports.size(); i++) {
// TODO: Fix port comparison
// if (ports[i] == port) {
if (ports[i].get_index() == port.get_index() && ports[i].get_names() == port.get_names() &&
check_nodes(ports[i].get_node(), port.get_node())) {
return {i, type};
std::lock_guard<std::mutex> lock(m_cache_mutex);
m_cached_ports[port_hash] = {i, type};
return m_cached_ports[port_hash];
}
}
type = ov::ISyncInferRequest::FoundPort::Type::OUTPUT;
@@ -275,10 +293,10 @@ void ov::ISyncInferRequest::allocate_tensor(
void ov::ISyncInferRequest::check_tensors() const {
const auto& inputs = m_compiled_model->inputs();
for (size_t i = 0; i < inputs.size(); i++) {
check_tensor(inputs[i], get_tensor_ptr(inputs[i]));
check_tensor(inputs[i], m_tensors.at(inputs[i].get_tensor_ptr()));
}
const auto& outputs = m_compiled_model->outputs();
for (size_t i = 0; i < outputs.size(); i++) {
check_tensor(outputs[i], get_tensor_ptr(outputs[i]));
check_tensor(outputs[i], m_tensors.at(outputs[i].get_tensor_ptr()));
}
}
+8 -13
View File
@@ -49,20 +49,15 @@ ov::hetero::InferRequest::InferRequest(const std::shared_ptr<const ov::hetero::C
ov::hetero::InferRequest::~InferRequest() = default;
ov::SoPtr<ov::IAsyncInferRequest> ov::hetero::InferRequest::get_request(const ov::Output<const ov::Node>& port) const {
auto check_nodes = [](const ov::Node* node1, const ov::Node* node2) {
return node1 == node2 ||
(node1->get_friendly_name() == node2->get_friendly_name() &&
node1->get_type_info() == node2->get_type_info() &&
node1->outputs().size() == node2->outputs().size() && node1->inputs().size() == node2->inputs().size());
};
for (const auto& kvp : m_port_to_subrequest_idx) {
if (kvp.first.get_index() == port.get_index() && kvp.first.get_names() == port.get_names() &&
check_nodes(kvp.first.get_node(), port.get_node())) {
return m_subrequests[kvp.second];
}
auto found_port = find_port(port);
ov::Output<const ov::Node> internal_port;
OPENVINO_ASSERT(found_port.found(), "Cannot find infer request for port ", port);
if (found_port.is_input()) {
internal_port = get_inputs().at(found_port.idx);
} else {
internal_port = get_outputs().at(found_port.idx);
}
OPENVINO_THROW("Cannot find infer request for port ", port);
return m_subrequests[m_port_to_subrequest_idx.at(internal_port)];
}
ov::SoPtr<ov::ITensor> ov::hetero::InferRequest::get_tensor(const ov::Output<const ov::Node>& port) const {