diff --git a/src/core/src/runtime/itensor.cpp b/src/core/src/runtime/itensor.cpp index 4a5d011122f068..67dde4e38aa463 100644 --- a/src/core/src/runtime/itensor.cpp +++ b/src/core/src/runtime/itensor.cpp @@ -6,6 +6,7 @@ #include +#include "compare.hpp" #include "openvino/core/except.hpp" #include "openvino/core/shape_util.hpp" #include "openvino/core/type/element_iterator.hpp" @@ -46,7 +47,21 @@ bool ITensor::is_continuous() const { // OpenVINO doesn't support strides for lp types return true; } - return default_byte_strides(get_shape(), get_element_type()) == get_strides(); + + const auto& strides = get_strides(); + auto stride = strides.rbegin(); + const auto default_strides = default_byte_strides(get_shape(), get_element_type()); + auto default_stride = default_strides.rbegin(); + + for (; stride != strides.rend(); ++stride, ++default_stride) { + if (*stride != *default_stride) { + break; + } + } + + const auto default_last = default_strides.rend(); + return (default_stride == default_last) || (*default_stride < *stride && (get_shape()[0] == 1) && + std::all_of(default_stride, default_last, cmp::Equal(*default_stride))); } void ITensor::copy_to(const std::shared_ptr& dst) const { diff --git a/src/core/tests/ov_tensor_test.cpp b/src/core/tests/ov_tensor_test.cpp index fdb4fa28416408..6a386f0a659246 100644 --- a/src/core/tests/ov_tensor_test.cpp +++ b/src/core/tests/ov_tensor_test.cpp @@ -709,6 +709,107 @@ TEST_F(OVTensorTest, readRangeRoiBlobStringTensor) { } } +TEST_F(OVTensorTest, checkIsContinuousTensorScalar) { + ov::Tensor tensor(ov::element::f32, ov::Shape{}); + auto data = tensor.data(); + auto strides = tensor.get_strides(); + + ov::Tensor view_tensor(ov::element::f32, ov::Shape{}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); +} + +TEST_F(OVTensorTest, checkIsContinuousTensor1Dimension) { + ov::Tensor tensor(ov::element::f32, ov::Shape{128}); + auto data = tensor.data(); + auto strides = tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{16}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); +} + +TEST_F(OVTensorTest, checkIsContinuousTensor2Dimensions) { + ov::Tensor tensor(ov::element::f32, ov::Shape{32, 128}); + auto data = tensor.data(); + auto strides = tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 16}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{2, 16}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); +} + +TEST_F(OVTensorTest, checkIsContinuousTensor3Dimensions) { + ov::Tensor tensor(ov::element::f32, ov::Shape{5, 32, 128}); + auto data = tensor.data(); + auto strides = tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{2, 32, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{2, 16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 1, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 1, 64}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); +} + +TEST_F(OVTensorTest, checkIsContinuousTensor4Dimensions) { + ov::Tensor tensor(ov::element::f32, ov::Shape{3, 5, 32, 128}); + auto data = tensor.data(); + auto strides = tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 2, 32, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{2, 5, 32, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{2, 2, 32, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 2, 5, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{3, 5, 32, 64}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 1, 16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{2, 1, 16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 1, 1, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{1, 1, 1, 32}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); +} + struct TestParams { ov::Shape src_shape; ov::Strides src_strides; diff --git a/src/plugins/intel_npu/tests/functional/behavior/remote_tensor_tests/remote_run.hpp b/src/plugins/intel_npu/tests/functional/behavior/remote_tensor_tests/remote_run.hpp index c1992b3047996d..b410ce70a5d3b8 100644 --- a/src/plugins/intel_npu/tests/functional/behavior/remote_tensor_tests/remote_run.hpp +++ b/src/plugins/intel_npu/tests/functional/behavior/remote_tensor_tests/remote_run.hpp @@ -93,6 +93,134 @@ class RemoteRunTests : public ov::test::behavior::OVPluginTestBase, } }; +TEST_P(RemoteRunTests, CheckIsContinuousHostTensorScalar) { + // Skip test according to plugin specific disabledTestPatterns() (if any) + SKIP_IF_CURRENT_TEST_IS_DISABLED() + + auto zero_context = core->get_default_context(target_device); + + auto host_tensor = zero_context.create_host_tensor(ov::element::f32, Shape{}); + auto data = host_tensor.data(); + auto strides = host_tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); +} + +TEST_P(RemoteRunTests, CheckIsContinuousHostTensor1Dimension) { + // Skip test according to plugin specific disabledTestPatterns() (if any) + SKIP_IF_CURRENT_TEST_IS_DISABLED() + + auto zero_context = core->get_default_context(target_device); + + auto host_tensor = zero_context.create_host_tensor(ov::element::f32, Shape{128}); + auto data = host_tensor.data(); + auto strides = host_tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, ov::Shape{16}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); +} + +TEST_P(RemoteRunTests, CheckIsContinuousHostTensor2Dimensions) { + // Skip test according to plugin specific disabledTestPatterns() (if any) + SKIP_IF_CURRENT_TEST_IS_DISABLED() + + auto zero_context = core->get_default_context(target_device); + + auto host_tensor = zero_context.create_host_tensor(ov::element::f32, Shape{32, 128}); + auto data = host_tensor.data(); + auto strides = host_tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, Shape{16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 16}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{2, 16}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); +} + +TEST_P(RemoteRunTests, CheckIsContinuousHostTensor3Dimensions) { + // Skip test according to plugin specific disabledTestPatterns() (if any) + SKIP_IF_CURRENT_TEST_IS_DISABLED() + + auto zero_context = core->get_default_context(target_device); + + auto host_tensor = zero_context.create_host_tensor(ov::element::f32, Shape{5, 32, 128}); + auto data = host_tensor.data(); + auto strides = host_tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, Shape{2, 32, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{2, 16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 1, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 1, 64}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); +} + +TEST_P(RemoteRunTests, CheckIsContinuousHostTensor4Dimensions) { + // Skip test according to plugin specific disabledTestPatterns() (if any) + SKIP_IF_CURRENT_TEST_IS_DISABLED() + + auto zero_context = core->get_default_context(target_device); + + auto host_tensor = zero_context.create_host_tensor(ov::element::f32, Shape{3, 5, 32, 128}); + auto data = host_tensor.data(); + auto strides = host_tensor.get_strides(); + + ov::Tensor view_tensor; + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 2, 32, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{2, 5, 32, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{2, 2, 32, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 2, 5, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, Shape{3, 5, 32, 64}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 1, 16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{2, 1, 16, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), false); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 1, 1, 128}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); + + view_tensor = ov::Tensor(ov::element::f32, Shape{1, 1, 1, 32}, data, strides); + EXPECT_EQ(view_tensor.is_continuous(), true); +} + TEST_P(RemoteRunTests, CheckRemoteTensorInternalBuf) { // Skip test according to plugin specific disabledTestPatterns() (if any) SKIP_IF_CURRENT_TEST_IS_DISABLED()