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:
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
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in new issue
Block a user