diff --git a/src/plugins/intel_cpu/src/cache/cache_entry.h b/src/plugins/intel_cpu/src/cache/cache_entry.h index f8e6c1fb1ee..e5028ae6903 100644 --- a/src/plugins/intel_cpu/src/cache/cache_entry.h +++ b/src/plugins/intel_cpu/src/cache/cache_entry.h @@ -55,10 +55,12 @@ public: } auto retStatus = LookUpStatus::Hit; ValType retVal = _impl.get(key); - if (retVal == ValType()) { + auto retEmpty = ValType(); + if (retVal == retEmpty) { retStatus = LookUpStatus::Miss; retVal = builder(key); - _impl.put(key, retVal); + if (retVal != retEmpty) + _impl.put(key, retVal); } return {retVal, retStatus}; } diff --git a/src/plugins/intel_cpu/src/nodes/mkldnn_reorder_node.cpp b/src/plugins/intel_cpu/src/nodes/mkldnn_reorder_node.cpp index 4ebeba5c587..ee81f7776e1 100644 --- a/src/plugins/intel_cpu/src/nodes/mkldnn_reorder_node.cpp +++ b/src/plugins/intel_cpu/src/nodes/mkldnn_reorder_node.cpp @@ -14,11 +14,39 @@ #include "nodes/common/cpu_memcpy.h" #include "nodes/common/cpu_convert.h" #include "mkldnn_convert_node.h" +#include using namespace mkldnn; using namespace MKLDNNPlugin; using namespace InferenceEngine; +namespace { +struct ReorderKey { + mkldnn::memory::desc src; + mkldnn::memory::desc dest; + size_t hash() const; + bool operator==(const ReorderKey& rhs) const; +}; + +size_t ReorderKey::hash() const { + using namespace dnnl::impl; + using namespace dnnl::impl::primitive_hashing; + + size_t seed = 0; + seed = hash_combine(seed, get_md_hash(src.data)); + seed = hash_combine(seed, get_md_hash(dest.data)); + + return seed; +} + +bool ReorderKey::operator==(const ReorderKey& rhs) const { + bool retVal = true; + retVal = src == rhs.src && dest == rhs.dest; + return retVal; +} + +} // namespace + bool MKLDNNReorderNode::isExecutable() const { return MKLDNNNode::isExecutable() && !isOptimized; } @@ -172,57 +200,67 @@ void MKLDNNReorderNode::prepareParams() { } } -void MKLDNNReorderNode::createReorderPrimitive(const mkldnn::memory::desc &srcDesc, void* srcPtr, const mkldnn::memory::desc &dstDesc, void* dstPtr) { - src_blocked = std::make_shared(getEngine()); +void MKLDNNReorderNode::createReorderPrimitive(const mkldnn::memory::desc& srcDesc, + void* srcPtr, + const mkldnn::memory::desc& dstDesc, + void* dstPtr) { + const auto engine = getEngine(); + src_blocked = std::make_shared(engine); src_blocked->Create(MKLDNNExtensionUtils::makeDescriptor(srcDesc), srcPtr, false); - dst_blocked = std::make_shared(getEngine()); + dst_blocked = std::make_shared(engine); dst_blocked->Create(MKLDNNExtensionUtils::makeDescriptor(dstDesc), dstPtr, false); - mkldnn::primitive_attr attr; - auto createReorder = [&]() -> bool { - // No autoblocking. Reorder can be applied as is - reorder::primitive_desc pd = mkldnn::reorder::primitive_desc(src_blocked->GetPrimitive(), dst_blocked->GetPrimitive(), attr, true); + impl_desc_type impl_type; + ReorderKey key = {src_blocked->GetPrimitive().get_desc(), dst_blocked->GetPrimitive().get_desc()}; + + auto builder = [&engine, &impl_type](const ReorderKey& key) -> std::shared_ptr { + mkldnn::primitive_attr attr; + reorder::primitive_desc pd = mkldnn::reorder::primitive_desc(engine, key.src, engine, key.dest, attr, true); if (!pd) - return false; - + return nullptr; auto info = pd.impl_info_str(); - supportedPrimitiveDescriptors[0].setImplementationType(parse_impl_name(info)); - - prim.reset(new mkldnn::reorder(pd)); - return true; + impl_type = parse_impl_name(info); + return std::make_shared(pd); }; - auto success = createReorder(); - if (!success) { - // TODO: We should keep shape consistency for const and expected shape for node. - // If it requires reshape operation it should explicitly injected into graph. - // - // There is a limitation for IE representing of weights for grouped convolutions. IE doesn't - // split group dimension in separate shape dimension. IE use OIHW, but mkldnn expect GOIHW. - // So we will perform implicit reshape to dst shape. - // - // MKLDNN doesn't support direct reorders for tensors of different rank. The code below tries to - // perform such conversion if the source tensor can be reshaped to the destination rank. This is - // useful in situations when rank in IR does not much rank that is required by the oneDNN primitive, - // but the input tensor can be reshaped (e.g. weights for grouped convolutions, biases etc.) - if (src_blocked->getDesc().hasLayoutType(LayoutType::ncsp) && - src_blocked->GetShape().getRank() != dst_blocked->GetShape().getRank()) { - const auto newDims = dst_blocked->getStaticDims(); - const auto newFormat = MKLDNNExtensionUtils::GetPlainFormatByRank(newDims.size()); + auto cache = getRuntimeCache(); + std::pair, CacheEntryBase::LookUpStatus> result{ + nullptr, + CacheEntryBase::LookUpStatus::Miss}; + // TODO: We should keep shape consistency for const and expected shape for node. + // If it requires reshape operation it should explicitly injected into graph. + // + // There is a limitation for IE representing of weights for grouped convolutions. IE doesn't + // split group dimension in separate shape dimension. IE use OIHW, but mkldnn expect GOIHW. + // So we will perform implicit reshape to dst shape. + // + // MKLDNN doesn't support direct reorders for tensors of different rank. The code below tries to + // perform such conversion if the source tensor can be reshaped to the destination rank. This is + // useful in situations when rank in IR does not much rank that is required by the oneDNN primitive, + // but the input tensor can be reshaped (e.g. weights for grouped convolutions, biases etc.) + if (src_blocked->getDesc().hasLayoutType(LayoutType::ncsp) && + src_blocked->GetShape().getRank() != dst_blocked->GetShape().getRank()) { + const auto newDims = dst_blocked->getStaticDims(); + const auto newFormat = MKLDNNExtensionUtils::GetPlainFormatByRank(newDims.size()); - auto newDesc = mkldnn::memory::desc(MKLDNNExtensionUtils::convertToDnnlDims(newDims), src_blocked->GetDataType(), newFormat); - src_blocked->Create(MKLDNNExtensionUtils::makeDescriptor(newDesc), srcPtr, false); + auto newDesc = mkldnn::memory::desc(MKLDNNExtensionUtils::convertToDnnlDims(newDims), + src_blocked->GetDataType(), + newFormat); + src_blocked->Create(MKLDNNExtensionUtils::makeDescriptor(newDesc), srcPtr, false); - success = createReorder(); - } + key.src = src_blocked->GetPrimitive().get_desc(); + result = cache->getOrCreate(key, builder); + } else { + result = cache->getOrCreate(key, builder); } - if (!success) { + if (!result.first) { IE_THROW() << "Cannot create reorder primitive: unsupported reorder case"; } - + prim = result.first; + supportedPrimitiveDescriptors[0].setImplementationType(impl_type); auto src = getParentEdgesAtPort(0)[0]->getMemoryPtr()->GetPrimitive(); auto dst = getChildEdgesAtPort(0)[0]->getMemoryPtr()->GetPrimitive(); primArgs = {{DNNL_ARG_SRC, src}, {DNNL_ARG_DST, dst}}; diff --git a/src/tests/functional/plugin/cpu/single_layer_tests/convolution.cpp b/src/tests/functional/plugin/cpu/single_layer_tests/convolution.cpp index add0d6d08ae..063953ca305 100755 --- a/src/tests/functional/plugin/cpu/single_layer_tests/convolution.cpp +++ b/src/tests/functional/plugin/cpu/single_layer_tests/convolution.cpp @@ -992,7 +992,9 @@ std::vector inputShapes_Reorder_2D = { // target static shapes { { 1, 32, 39, 40 }, - { 2, 32, 20, 20} + { 2, 32, 20, 20 }, + { 1, 32, 39, 40 }, + { 2, 32, 20, 20 } } } }; diff --git a/src/tests/unit/cpu/nodes/mkldnn_reorder_node.cpp b/src/tests/unit/cpu/nodes/mkldnn_reorder_node.cpp index 0d39ff48027..27b30dafb60 100644 --- a/src/tests/unit/cpu/nodes/mkldnn_reorder_node.cpp +++ b/src/tests/unit/cpu/nodes/mkldnn_reorder_node.cpp @@ -9,6 +9,8 @@ #include "mkldnn_input_node.h" #include "mkldnn_edge.h" #include "mkldnn_node.h" +#include "cache/multi_cache.h" + /* * Test MKLDNNReorderNode::optimizedNcsp2Nspc() and MKLDNNReorderNode::optimizedNspc2Ncsp() for * inPlace and non-inPlace cases. Specifically, the test checks that dst batch strides are @@ -71,6 +73,7 @@ protected: childEdge->changeStatus(MKLDNNPlugin::MKLDNNEdge::Status::NeedAllocation); reorderNode->addEdge(parentEdge); reorderNode->addEdge(childEdge); + auto rtParamsCache = std::make_shared(100); const std::vector srcBlockedDims = getBlockedDims(srcDims, srcOrder); const std::vector srcStrides = getStrides(srcBlockedDims); @@ -95,6 +98,7 @@ protected: childEdge->reuse(childMemory); reorderNode->setDescs(inputDesc, outputDesc); + reorderNode->setRuntimeCache(rtParamsCache); std::vector> nodes {inputNode, reorderNode, outputNode}; for (auto &n : nodes) { n->init();