diff --git a/src/plugins/intel_cpu/src/infer_request.cpp b/src/plugins/intel_cpu/src/infer_request.cpp index f2aacbd3db4..749342edae1 100644 --- a/src/plugins/intel_cpu/src/infer_request.cpp +++ b/src/plugins/intel_cpu/src/infer_request.cpp @@ -214,6 +214,19 @@ static inline void changeEdgePtr(const EdgePtr &edge, InferenceEngine::Blob::Ptr void InferRequestBase::changeDefaultPtr() { const auto& inputNodesMap = graph->GetInputNodesMap(); const auto& outputNodesMap = graph->GetOutputNodesMap(); + std::unordered_set inputPtrs; + std::function changeInpPtr; + if (Graph::Status::ReadyDynamic == graph->getStatus()) { + changeInpPtr = [&inputPtrs](const EdgePtr &edge, InferenceEngine::Blob::Ptr blob) { + changeEdgePtr(edge, blob); + inputPtrs.insert(blob->buffer()); + }; + } else { + changeInpPtr = [](const EdgePtr &edge, InferenceEngine::Blob::Ptr blob) { + changeEdgePtr(edge, blob); + }; + } + for (auto& it : externalPtr) { auto input = inputNodesMap.find(it.first); if (inputNodesMap.end() == input) { @@ -261,7 +274,7 @@ void InferRequestBase::changeDefaultPtr() { if (!e) IE_THROW() << "Node " << inputNodePtr->getName() << " contains empty child edge"; - changeEdgePtr(e, it.second); + changeInpPtr(e, it.second); } } } @@ -321,18 +334,9 @@ void InferRequestBase::changeDefaultPtr() { OPENVINO_ASSERT(outputNodesMap.end() != output, "Node with name: ", name, " is absent in the outputNodesMap"); auto parentEdge = output->second->getParentEdgeAt(0); //avoid cyclic memory use - auto parentNode = parentEdge->getParent(); - const auto& parentNodeInpEdges = parentNode->getParentEdges(); - std::unordered_set parentInputPtrs(parentNodeInpEdges.size()); - for (auto&& edge : parentNodeInpEdges) { - if (auto edgePtr = edge.lock()) { - parentInputPtrs.insert(edgePtr->getMemoryPtr()->getData()); - } - } - auto&& controlBlock = controlBlockItr->second; - std::shared_ptr memMngr = parentInputPtrs.count(controlBlock.rawPtr()) ? // same memory is used on the input and output + std::shared_ptr memMngr = inputPtrs.count(controlBlock.rawPtr()) ? // same memory is used on the input and output controlBlock.nextMemMngr() : // then swap internal buffer to avoid data corruption controlBlock.currentMemMngr(); // else reuse the existing buffer diff --git a/src/plugins/intel_cpu/tests/functional/subgraph_tests/src/concat_reshape_concat.cpp b/src/plugins/intel_cpu/tests/functional/subgraph_tests/src/concat_reshape_concat.cpp index 41507b4ae9e..57f75c12388 100644 --- a/src/plugins/intel_cpu/tests/functional/subgraph_tests/src/concat_reshape_concat.cpp +++ b/src/plugins/intel_cpu/tests/functional/subgraph_tests/src/concat_reshape_concat.cpp @@ -122,13 +122,13 @@ TEST_P(ConcatReshapeConcatSubgraphTest, CompareWithRefs) { namespace { const std::vector> inputShapes = { - // { - // // {{dynamic shape}, {{static shape case1}, {static shape case2}, ...} - // {{2, 64}, {{2, 64}}}, // input 0 - // {{2, 64}, {{2, 64}}}, // input 1 - // {{2, 64}, {{2, 64}}}, // input 2 - // {{2, 64}, {{2, 64}}} // input 3 - // }, + { + // {{dynamic shape}, {{static shape case1}, {static shape case2}, ...} + {{2, 64}, {{2, 64}}}, // input 0 + {{2, 64}, {{2, 64}}}, // input 1 + {{2, 64}, {{2, 64}}}, // input 2 + {{2, 64}, {{2, 64}}} // input 3 + }, { // {{dynamic shape}, {{static shape case1}, {static shape case2}, ...} {{2, -1}, {{2, 64}}}, // input 0 diff --git a/src/plugins/intel_cpu/tests/functional/subgraph_tests/src/input_output_tensor_reuse.cpp b/src/plugins/intel_cpu/tests/functional/subgraph_tests/src/input_output_tensor_reuse.cpp new file mode 100644 index 00000000000..f26ed8d1f8d --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/subgraph_tests/src/input_output_tensor_reuse.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "ngraph_functions/utils/ngraph_helpers.hpp" +#include "ngraph_functions/builders.hpp" + +using namespace InferenceEngine; +using namespace ov::test; + +/*This test runs the following subgraph: + + + Param_0 Param_1 + \ | + \ Softmax + \ / + \ / + Concat + | + Softmax + | + Output_1 + + Output_1 -> Param_1 + + The main purpose of this test is checking the code path when the output tensor is reused as an input tensor of the + next infer request. +*/ + +namespace SubgraphTestsDefinitions { +class InputOutputTensorReuse : public SubgraphBaseTest { +public: + void SetUp() override { + constexpr size_t softmax_axis = 1ul; + constexpr int concat_axis = 2; + targetDevice = ov::test::utils::DEVICE_CPU; + auto netPrc = ov::element::f32; + + ov::ParameterVector input_params; + input_params.push_back(std::make_shared(netPrc, ov::PartialShape{1, 32, -1, 16})); + input_params.push_back(std::make_shared(netPrc, ov::PartialShape{1, 32, -1, 16})); + input_params[0]->set_friendly_name("Param_0"); + input_params[1]->set_friendly_name("Param_1"); + + auto first_soft_max = std::make_shared(input_params[1], softmax_axis); + auto concat = std::make_shared(ov::NodeVector{input_params[0], first_soft_max}, concat_axis); + auto last_soft_max = std::make_shared(concat, softmax_axis); + + ngraph::ResultVector results; + for (size_t i = 0; i < last_soft_max->get_output_size(); i++) + results.push_back(std::make_shared(last_soft_max->output(i))); + + results.front()->set_friendly_name("Output_1"); + + function = std::make_shared(results, input_params, "InputOutputTensorReuseTest"); + } +}; + +TEST_F(InputOutputTensorReuse, smoke_Input_Output_Binding) { + compile_model(); + std::vector inputShapes = {{1, 32, 5, 16}, {1, 32, 1, 16}}; + init_ref_function(functionRefs, inputShapes); + generate_inputs(inputShapes); + validate(); + + constexpr size_t num_iter = 10; + for (size_t i = 0; i < num_iter; i++) { + auto outputTensor = inferRequest.get_output_tensor(0); + inputShapes.back() = outputTensor.get_shape(); + init_ref_function(functionRefs, inputShapes); + auto itr = std::find_if(inputs.begin(), inputs.end(), [](const std::pair, ov::Tensor>& item) { + return item.first->get_friendly_name() == "Param_1"; + }); + ASSERT_NE(itr, inputs.end()); + itr->second = outputTensor; + const auto& expectedOutputs = calculate_refs(); + + for (const auto& input : inputs) { + inferRequest.set_tensor(input.first, input.second); + } + inferRequest.infer(); + compare(expectedOutputs, {outputTensor}); + } +} + +} // namespace SubgraphTestsDefinitions \ No newline at end of file