Introduce ITensor instead of Blob (#16048)

* Introduce ITensor

* Added new allocator

* Hide ITensor from dev api

* Changed some python tests

* Remove deprecated API from sample

* Fixed warnings

* Skiped unsupported tests

* Fixed exception message

* Fixed template func tests

* Fixed incorrect tests

* Fixed comments and move ITensor to developer API

* Fixed CI issue

* Fixed allocated tensor

* Fixed docs and windows warning

* Fixed set shape for strided tensors

* Fixed build and some comments

* Introduce remote tensor

* Fixed code style

* Fixed build

* Remove static assert method

* Remove fail type

* Added device name API

* Try to fix GPU remote tests

* Added debug output

* Try to fix GPU tests

* Fixed comments

* Fixed build

* Added additional element type check

* Revert some comment changes
This commit is contained in:
Ilya Churaev 2023-03-14 19:12:27 +04:00 committed by GitHub
parent 596036a2db
commit 95faa573ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1122 additions and 285 deletions

View File

@ -15,7 +15,6 @@
#include "format_reader_ptr.h" #include "format_reader_ptr.h"
#include "samples/slog.hpp" #include "samples/slog.hpp"
#include "shared_tensor_allocator.hpp"
#include "utils.hpp" #include "utils.hpp"
template <typename T> template <typename T>
@ -31,10 +30,8 @@ ov::Tensor create_tensor_from_image(const std::vector<std::string>& files,
const benchmark_app::InputInfo& inputInfo, const benchmark_app::InputInfo& inputInfo,
const std::string& inputName, const std::string& inputName,
std::string* filenames_used = nullptr) { std::string* filenames_used = nullptr) {
size_t tensor_size = auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape);
std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>()); auto data = tensor.data<T>();
auto allocator = std::make_shared<SharedTensorAllocator>(tensor_size * sizeof(T));
auto data = reinterpret_cast<T*>(allocator->get_buffer());
/** Collect images data ptrs **/ /** Collect images data ptrs **/
std::vector<std::shared_ptr<uint8_t>> vreader; std::vector<std::shared_ptr<uint8_t>> vreader;
@ -90,7 +87,6 @@ ov::Tensor create_tensor_from_image(const std::vector<std::string>& files,
} }
} }
auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape, ov::Allocator(allocator));
return tensor; return tensor;
} }
@ -103,8 +99,8 @@ ov::Tensor create_tensor_from_numpy(const std::vector<std::string>& files,
std::string* filenames_used = nullptr) { std::string* filenames_used = nullptr) {
size_t tensor_size = size_t tensor_size =
std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>()); std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>());
auto allocator = std::make_shared<SharedTensorAllocator>(tensor_size * sizeof(T)); auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape);
auto data = reinterpret_cast<T*>(allocator->get_buffer()); auto data = tensor.data<T>();
std::vector<std::shared_ptr<unsigned char>> numpy_array_pointers; std::vector<std::shared_ptr<unsigned char>> numpy_array_pointers;
numpy_array_pointers.reserve(batchSize); numpy_array_pointers.reserve(batchSize);
@ -150,7 +146,7 @@ ov::Tensor create_tensor_from_numpy(const std::vector<std::string>& files,
} }
} }
return ov::Tensor(inputInfo.type, inputInfo.dataShape, ov::Allocator(allocator)); return tensor;
} }
template <typename T> template <typename T>
@ -160,8 +156,8 @@ ov::Tensor create_tensor_im_info(const std::pair<size_t, size_t>& image_size,
const std::string& inputName) { const std::string& inputName) {
size_t tensor_size = size_t tensor_size =
std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>()); std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>());
auto allocator = std::make_shared<SharedTensorAllocator>(tensor_size * sizeof(T)); auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape);
auto data = reinterpret_cast<T*>(allocator->get_buffer()); char* data = static_cast<char*>(tensor.data());
size_t infoBatchSize = 1; size_t infoBatchSize = 1;
if (!inputInfo.layout.empty() && ov::layout::has_batch(inputInfo.layout)) { if (!inputInfo.layout.empty() && ov::layout::has_batch(inputInfo.layout)) {
@ -176,15 +172,14 @@ ov::Tensor create_tensor_im_info(const std::pair<size_t, size_t>& image_size,
for (size_t i = 0; i < iminfoSize; i++) { for (size_t i = 0; i < iminfoSize; i++) {
size_t index = b * iminfoSize + i; size_t index = b * iminfoSize + i;
if (0 == i) if (0 == i)
data[index] = static_cast<T>(image_size.first); data[index] = static_cast<char>(image_size.first);
else if (1 == i) else if (1 == i)
data[index] = static_cast<T>(image_size.second); data[index] = static_cast<char>(image_size.second);
else else
data[index] = 1; data[index] = static_cast<char>(1);
} }
} }
auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape, ov::Allocator(allocator));
return tensor; return tensor;
} }
@ -197,8 +192,8 @@ ov::Tensor create_tensor_from_binary(const std::vector<std::string>& files,
std::string* filenames_used = nullptr) { std::string* filenames_used = nullptr) {
size_t tensor_size = size_t tensor_size =
std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>()); std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>());
auto allocator = std::make_shared<SharedTensorAllocator>(tensor_size * sizeof(T)); auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape);
char* data = allocator->get_buffer(); char* data = static_cast<char*>(tensor.data());
size_t binaryBatchSize = 1; size_t binaryBatchSize = 1;
if (!inputInfo.layout.empty() && ov::layout::has_batch(inputInfo.layout)) { if (!inputInfo.layout.empty() && ov::layout::has_batch(inputInfo.layout)) {
binaryBatchSize = batchSize; binaryBatchSize = batchSize;
@ -245,7 +240,6 @@ ov::Tensor create_tensor_from_binary(const std::vector<std::string>& files,
} }
} }
auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape, ov::Allocator(allocator));
return tensor; return tensor;
} }
@ -255,8 +249,8 @@ ov::Tensor create_tensor_random(const benchmark_app::InputInfo& inputInfo,
T rand_max = std::numeric_limits<uint8_t>::max()) { T rand_max = std::numeric_limits<uint8_t>::max()) {
size_t tensor_size = size_t tensor_size =
std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>()); std::accumulate(inputInfo.dataShape.begin(), inputInfo.dataShape.end(), 1, std::multiplies<size_t>());
auto allocator = std::make_shared<SharedTensorAllocator>(tensor_size * sizeof(T)); auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape);
auto data = reinterpret_cast<T*>(allocator->get_buffer()); auto data = tensor.data<T>();
std::mt19937 gen(0); std::mt19937 gen(0);
uniformDistribution<T2> distribution(rand_min, rand_max); uniformDistribution<T2> distribution(rand_min, rand_max);
@ -264,7 +258,6 @@ ov::Tensor create_tensor_random(const benchmark_app::InputInfo& inputInfo,
data[i] = static_cast<T>(distribution(gen)); data[i] = static_cast<T>(distribution(gen));
} }
auto tensor = ov::Tensor(inputInfo.type, inputInfo.dataShape, ov::Allocator(allocator));
return tensor; return tensor;
} }

View File

@ -1,42 +0,0 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "openvino/runtime/allocator.hpp"
class SharedTensorAllocator : public ov::AllocatorImpl {
public:
SharedTensorAllocator(size_t sizeBytes) : size(sizeBytes) {
data = new char[size];
}
~SharedTensorAllocator() {
delete[] data;
}
virtual void* allocate(const size_t bytes, const size_t) override {
return bytes <= this->size ? (void*)data : nullptr;
}
void deallocate(void* handle, const size_t bytes, const size_t) override {
if (handle == data) {
delete[] data;
data = nullptr;
}
}
bool is_equal(const AllocatorImpl& other) const override {
auto other_tensor_allocator = dynamic_cast<const SharedTensorAllocator*>(&other);
return other_tensor_allocator != nullptr && other_tensor_allocator == this;
}
char* get_buffer() {
return data;
}
private:
char* data;
size_t size;
};

View File

@ -241,7 +241,7 @@ def test_cannot_set_bigger_shape_on_preallocated_memory():
assert np.shares_memory(ones_arr, ov_tensor.data) assert np.shares_memory(ones_arr, ov_tensor.data)
with pytest.raises(RuntimeError) as e: with pytest.raises(RuntimeError) as e:
ov_tensor.shape = ref_shape ov_tensor.shape = ref_shape
assert "Cannot call setShape for Blobs created on top of preallocated memory" in str(e.value) assert "failed" in str(e.value)
@pytest.mark.skip(reason="no support yet") @pytest.mark.skip(reason="no support yet")
@ -258,11 +258,11 @@ def test_can_reset_shape_after_decreasing_on_preallocated_memory():
assert list(ov_tensor.shape) == ref_shape_2 assert list(ov_tensor.shape) == ref_shape_2
def test_cannot_set_shape_incorrect_dims(): def test_can_set_shape_other_dims():
ov_tensor = Tensor(np.float32, [1, 3, 48, 48]) ov_tensor = Tensor(np.float32, [1, 3, 48, 48])
with pytest.raises(RuntimeError) as e: ref_shape_1 = [3, 28, 28]
ov_tensor.shape = [3, 28, 28] ov_tensor.shape = ref_shape_1
assert "Dims and format are inconsistent" in str(e.value) assert list(ov_tensor.shape) == ref_shape_1
@pytest.mark.parametrize("ov_type", [ @pytest.mark.parametrize("ov_type", [

View File

@ -23,6 +23,7 @@ add_subdirectory(shape_inference)
set(MIXED_SRC set(MIXED_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/allocator.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/allocator.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/itensor.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/ov_tensor.cpp") "${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/ov_tensor.cpp")
set_property(SOURCE ${MIXED_SRC} set_property(SOURCE ${MIXED_SRC}

View File

@ -0,0 +1,76 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include "openvino/core/coordinate.hpp"
#include "openvino/core/core_visibility.hpp"
#include "openvino/core/shape.hpp"
#include "openvino/core/type/element_type.hpp"
#include "openvino/runtime/allocator.hpp"
namespace ov {
class OPENVINO_API ITensor : public std::enable_shared_from_this<ITensor> {
public:
/**
* @brief Set new shape for tensor
* @note Memory allocation may happen
* @param shape A new shape
*/
virtual void set_shape(ov::Shape shape) = 0;
/**
* @return A tensor element type
*/
virtual const element::Type& get_element_type() const = 0;
/**
* @return A tensor shape
*/
virtual const Shape& get_shape() const = 0;
/**
* @brief Returns the total number of elements (a product of all the dims or 1 for scalar)
* @return The total number of elements
*/
virtual size_t get_size() const;
/**
* @brief Returns the size of the current Tensor in bytes.
* @return Tensor's size in bytes
*/
virtual size_t get_byte_size() const;
/**
* @return Tensor's strides in bytes
*/
virtual const Strides& get_strides() const = 0;
/**
* @brief Provides an access to the underlaying host memory
* @param type Optional type parameter.
* @note If type parameter is specified, the method throws an exception
* if specified type's fundamental type does not match with tensor element type's fundamental type
* @return A host pointer to tensor memory
*/
virtual void* data(const element::Type& type = {}) const = 0;
/**
* @brief Provides an access to the underlaying host memory casted to type `T`
* @return A host pointer to tensor memory casted to specified type `T`.
* @note Throws exception if specified type does not match with tensor element type
*/
template <typename T, typename datatype = typename std::decay<T>::type>
T* data() const {
return static_cast<T*>(data(element::from<datatype>()));
}
protected:
virtual ~ITensor();
};
} // namespace ov

View File

@ -29,6 +29,9 @@ class Plugin;
/** @cond INTERNAL */ /** @cond INTERNAL */
class Any; class Any;
namespace util { namespace util {
OPENVINO_API bool equal(std::type_index lhs, std::type_index rhs);
template <typename T, typename = void> template <typename T, typename = void>
struct Read; struct Read;
@ -416,8 +419,6 @@ class OPENVINO_API Any {
} }
}; };
static bool equal(std::type_index lhs, std::type_index rhs);
class OPENVINO_API Base : public std::enable_shared_from_this<Base> { class OPENVINO_API Base : public std::enable_shared_from_this<Base> {
public: public:
void type_check(const std::type_info&) const; void type_check(const std::type_info&) const;
@ -731,7 +732,7 @@ public:
return true; return true;
} }
for (const auto& type_index : _impl->base_type_info()) { for (const auto& type_index : _impl->base_type_info()) {
if (equal(type_index, typeid(decay_t<T>))) { if (util::equal(type_index, typeid(decay_t<T>))) {
return true; return true;
} }
} }
@ -797,7 +798,7 @@ public:
return *static_cast<decay_t<T>*>(_temp->addressof()); return *static_cast<decay_t<T>*>(_temp->addressof());
} }
for (const auto& type_index : _impl->base_type_info()) { for (const auto& type_index : _impl->base_type_info()) {
if (equal(type_index, typeid(decay_t<T>))) { if (util::equal(type_index, typeid(decay_t<T>))) {
return *static_cast<decay_t<T>*>(_impl->addressof()); return *static_cast<decay_t<T>*>(_impl->addressof());
} }
} }
@ -820,7 +821,7 @@ public:
return *static_cast<decay_t<T>*>(_impl->addressof()); return *static_cast<decay_t<T>*>(_impl->addressof());
} }
for (const auto& type_index : _impl->base_type_info()) { for (const auto& type_index : _impl->base_type_info()) {
if (equal(type_index, typeid(decay_t<T>))) { if (util::equal(type_index, typeid(decay_t<T>))) {
return *static_cast<decay_t<T>*>(_impl->addressof()); return *static_cast<decay_t<T>*>(_impl->addressof());
} }
} }

View File

@ -12,15 +12,20 @@
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include "openvino/core/any.hpp"
#include "openvino/core/core_visibility.hpp" #include "openvino/core/core_visibility.hpp"
#include "openvino/core/deprecated.hpp"
namespace ov { namespace ov {
/** /**
* @interface AllocatorImpl * @interface AllocatorImpl
* @deprecated This class will be removed in 2024.0 release
* @brief Tries to act like [std::pmr::memory_resource](https://en.cppreference.com/w/cpp/memory/memory_resource) * @brief Tries to act like [std::pmr::memory_resource](https://en.cppreference.com/w/cpp/memory/memory_resource)
*/ */
struct AllocatorImpl : public std::enable_shared_from_this<AllocatorImpl> { struct OPENVINO_DEPRECATED("Do not inherit from AllocatorImpl. This class will be removed in 2024.0 release. Pass "
"std::pmr::memory_resource like object directly to ov::Allocator") AllocatorImpl
: public std::enable_shared_from_this<AllocatorImpl> {
/** /**
* @brief A smart pointer containing AllocatorImpl object * @brief A smart pointer containing AllocatorImpl object
*/ */
@ -61,22 +66,63 @@ class Tensor;
/** /**
* @brief Wraps allocator implementation to provide safe way to store allocater loaded from shared library * @brief Wraps allocator implementation to provide safe way to store allocater loaded from shared library
* And constructs default based on `new` `delete` c++ calls allocator if created without parameters * And constructs default based on `new` `delete` c++ calls allocator if created without parameters
* Accepts any [std::pmr::memory_resource](https://en.cppreference.com/w/cpp/memory/memory_resource) like
* allocator
* @ingroup ov_runtime_cpp_api * @ingroup ov_runtime_cpp_api
*/ */
class OPENVINO_API Allocator { class OPENVINO_API Allocator {
AllocatorImpl::Ptr _impl;
std::shared_ptr<void> _so;
/** /**
* @brief Constructs Tensor from the initialized std::shared_ptr * @brief Constructs Tensor from the initialized std::shared_ptr
* @param impl Initialized shared pointer * @param other Initialized allocator
* @param so Plugin to use. This is required to ensure that Allocator can work properly even if plugin object is * @param so Plugin to use. This is required to ensure that Allocator can work properly even if plugin object is
* destroyed. * destroyed.
*/ */
Allocator(const AllocatorImpl::Ptr& impl, const std::shared_ptr<void>& so); Allocator(const Allocator& other, const std::shared_ptr<void>& so);
friend class ov::Tensor; friend class ov::Tensor;
struct Base : public std::enable_shared_from_this<Base> {
virtual void* addressof() = 0;
const void* addressof() const {
return const_cast<Base*>(this)->addressof();
}
virtual const std::type_info& type_info() const = 0;
virtual void* allocate(const size_t bytes, const size_t alignment = alignof(max_align_t)) = 0;
virtual void deallocate(void* handle, const size_t bytes, size_t alignment = alignof(max_align_t)) = 0;
virtual bool is_equal(const Base& other) const = 0;
protected:
~Base() = default;
};
template <typename A>
struct Impl : public Base {
template <typename... Args>
explicit Impl(Args&&... args) : a(std::forward<Args>(args)...) {}
void* addressof() override {
return &a;
}
const std::type_info& type_info() const override {
return typeid(a);
}
void* allocate(const size_t bytes, const size_t alignment = alignof(max_align_t)) override {
return a.allocate(bytes, alignment);
}
void deallocate(void* handle, const size_t bytes, size_t alignment = alignof(max_align_t)) override {
a.deallocate(handle, bytes, alignment);
}
bool is_equal(const Base& other) const override {
if (util::equal(type_info(), other.type_info())) {
return a.is_equal(*static_cast<const A*>(other.addressof()));
}
return false;
}
A a;
};
std::shared_ptr<Base> _impl;
std::shared_ptr<void> _so;
public: public:
/** /**
* @brief Destructor preserves unloading order of implementation object and reference to library * @brief Destructor preserves unloading order of implementation object and reference to library
@ -104,11 +150,26 @@ public:
/// @return reference to the current object /// @return reference to the current object
Allocator& operator=(Allocator&& other) = default; Allocator& operator=(Allocator&& other) = default;
OPENVINO_SUPPRESS_DEPRECATED_START
/** /**
* @brief Constructs Allocator from the initialized std::shared_ptr * @brief Constructs Allocator from the initialized std::shared_ptr
* @param impl Initialized shared pointer * @param impl Initialized shared pointer
*/ */
Allocator(const AllocatorImpl::Ptr& impl); Allocator(const AllocatorImpl::Ptr& impl);
/**
* @brief Initialize allocator using any allocator like object
* @tparam A Type of allocator
* @param a allocator object
*/
template <
typename A,
typename std::enable_if<!std::is_convertible<A, AllocatorImpl::Ptr>::value &&
!std::is_same<typename std::decay<A>::type, Allocator>::value &&
!std::is_abstract<typename std::decay<A>::type>::value &&
!std::is_convertible<typename std::decay<A>::type, std::shared_ptr<Base>>::value,
bool>::type = true>
Allocator(A&& a) : _impl{std::make_shared<Impl<typename std::decay<A>::type>>(std::forward<A>(a))} {}
OPENVINO_SUPPRESS_DEPRECATED_END
/** /**
* @brief Allocates memory * @brief Allocates memory
@ -129,9 +190,9 @@ public:
void deallocate(void* ptr, const size_t bytes = 0, const size_t alignment = alignof(max_align_t)); void deallocate(void* ptr, const size_t bytes = 0, const size_t alignment = alignof(max_align_t));
/** /**
* @brief Compares with other AllocatorImpl * @brief Compares with other Allocator
* @param other Other instance of allocator * @param other Other instance of allocator
* @return `true` if and only if memory allocated from one AllocatorImpl can be deallocated from the other and vice * @return `true` if and only if memory allocated from one Allocator can be deallocated from the other and vice
* versa * versa
*/ */
bool operator==(const Allocator& other) const; bool operator==(const Allocator& other) const;
@ -149,9 +210,11 @@ public:
explicit operator bool() const noexcept; explicit operator bool() const noexcept;
}; };
OPENVINO_SUPPRESS_DEPRECATED_START
namespace runtime { namespace runtime {
using ov::Allocator; using ov::Allocator;
using ov::AllocatorImpl; using ov::AllocatorImpl;
} // namespace runtime } // namespace runtime
OPENVINO_SUPPRESS_DEPRECATED_END
} // namespace ov } // namespace ov

View File

@ -18,7 +18,6 @@
#include "openvino/runtime/allocator.hpp" #include "openvino/runtime/allocator.hpp"
namespace InferenceEngine { namespace InferenceEngine {
class Blob;
class IAsyncInferRequestWrapper; class IAsyncInferRequestWrapper;
class IVariableStateWrapper; class IVariableStateWrapper;
} // namespace InferenceEngine } // namespace InferenceEngine
@ -33,6 +32,8 @@ class VariableState;
class ISyncInferRequest; class ISyncInferRequest;
class IInferRequestInternalWrapper; class IInferRequestInternalWrapper;
class IVariableStateInternalWrapper; class IVariableStateInternalWrapper;
class ITensor;
class RemoteTensor;
/** /**
* @brief Tensor API holding host memory * @brief Tensor API holding host memory
@ -41,8 +42,8 @@ class IVariableStateInternalWrapper;
*/ */
class OPENVINO_API Tensor { class OPENVINO_API Tensor {
protected: protected:
std::shared_ptr<InferenceEngine::Blob> _impl; //!< Shared pointer to internal tensor representation std::shared_ptr<ITensor> _impl; //!< Shared pointer to internal tensor representation
std::vector<std::shared_ptr<void>> _so; //!< Reference to dynamically loaded library std::vector<std::shared_ptr<void>> _so; //!< Reference to dynamically loaded library
/** /**
* @brief Constructs Tensor from the initialized std::shared_ptr * @brief Constructs Tensor from the initialized std::shared_ptr
@ -50,11 +51,12 @@ protected:
* @param so Plugin to use. This is required to ensure that Tensor can work properly even if plugin object is * @param so Plugin to use. This is required to ensure that Tensor can work properly even if plugin object is
* destroyed. * destroyed.
*/ */
Tensor(const std::shared_ptr<InferenceEngine::Blob>& impl, const std::vector<std::shared_ptr<void>>& so); Tensor(const std::shared_ptr<ITensor>& impl, const std::vector<std::shared_ptr<void>>& so);
friend class ov::Core; friend class ov::Core;
friend class ov::CoreImpl; friend class ov::CoreImpl;
friend class ov::InferRequest; friend class ov::InferRequest;
friend class ov::RemoteTensor;
friend class ov::RemoteContext; friend class ov::RemoteContext;
friend class ov::VariableState; friend class ov::VariableState;
friend class ov::ISyncInferRequest; friend class ov::ISyncInferRequest;
@ -103,7 +105,7 @@ public:
* @param shape Tensor shape * @param shape Tensor shape
* @param allocator allocates memory for internal tensor storage * @param allocator allocates memory for internal tensor storage
*/ */
Tensor(const element::Type type, const Shape& shape, const Allocator& allocator = {}); Tensor(const element::Type& type, const Shape& shape, const Allocator& allocator = {});
/** /**
* @brief Constructs Tensor using element type and shape. Wraps allocated host memory. * @brief Constructs Tensor using element type and shape. Wraps allocated host memory.
@ -114,7 +116,7 @@ public:
* @param strides Optional strides parameters in bytes. Strides are supposed to be computed automatically based * @param strides Optional strides parameters in bytes. Strides are supposed to be computed automatically based
* on shape and element size * on shape and element size
*/ */
Tensor(const element::Type type, const Shape& shape, void* host_ptr, const Strides& strides = {}); Tensor(const element::Type& type, const Shape& shape, void* host_ptr, const Strides& strides = {});
/** /**
* @brief Constructs Tensor using port from node. Allocate internal host storage using default allocator * @brief Constructs Tensor using port from node. Allocate internal host storage using default allocator
@ -153,12 +155,12 @@ public:
/** /**
* @return A tensor element type * @return A tensor element type
*/ */
element::Type get_element_type() const; const element::Type& get_element_type() const;
/** /**
* @return A tensor shape * @return A tensor shape
*/ */
Shape get_shape() const; const Shape& get_shape() const;
/** /**
* @brief Copy tensor, destination tensor should have the same element type and shape * @brief Copy tensor, destination tensor should have the same element type and shape
@ -198,7 +200,7 @@ public:
* if specified type's fundamental type does not match with tensor element type's fundamental type * if specified type's fundamental type does not match with tensor element type's fundamental type
* @return A host pointer to tensor memory * @return A host pointer to tensor memory
*/ */
void* data(const element::Type type = {}) const; void* data(const element::Type& type = {}) const;
/** /**
* @brief Provides an access to the underlaying host memory casted to type `T` * @brief Provides an access to the underlaying host memory casted to type `T`

View File

@ -9,7 +9,7 @@
namespace ov { namespace ov {
bool Any::equal(std::type_index lhs, std::type_index rhs) { bool util::equal(std::type_index lhs, std::type_index rhs) {
auto result = lhs == rhs; auto result = lhs == rhs;
#if (defined(__ANDROID__) || defined(__APPLE__)) && defined(__clang__) #if (defined(__ANDROID__) || defined(__APPLE__)) && defined(__clang__)
if (!result) { if (!result) {
@ -20,7 +20,7 @@ bool Any::equal(std::type_index lhs, std::type_index rhs) {
} }
bool Any::Base::is(const std::type_info& other) const { bool Any::Base::is(const std::type_info& other) const {
return Any::equal(type_info(), other); return util::equal(type_info(), other);
} }
void Any::Base::type_check(const std::type_info& type_info_) const { void Any::Base::type_check(const std::type_info& type_info_) const {

View File

@ -11,19 +11,68 @@
namespace ov { namespace ov {
Allocator::Allocator() : _impl{std::make_shared<BlobAllocator>()} {} struct DefaultAllocator {
void* allocate(const size_t bytes, const size_t alignment) {
if (alignment == alignof(max_align_t)) {
return ::operator new(bytes);
} else {
OPENVINO_ASSERT(alignment && !static_cast<bool>(alignment & (alignment - static_cast<size_t>(1))),
"Alignment is not power of 2: ",
alignment);
#if defined(_WIN32)
return _aligned_malloc(bytes, alignment);
#else
void* result = nullptr;
if (posix_memalign(&result, std::max(sizeof(void*), alignment), bytes) != 0) {
OPENVINO_THROW("posix_memalign failed");
}
return result;
#endif
}
}
void deallocate(void* handle, const size_t bytes, const size_t alignment) {
if (alignment == alignof(max_align_t)) {
::operator delete(handle);
} else {
#if defined(_WIN32)
return _aligned_free(handle);
#else
return free(handle);
#endif
}
}
bool is_equal(const DefaultAllocator&) const {
return true;
}
};
Allocator::Allocator() : Allocator{DefaultAllocator{}} {}
OPENVINO_SUPPRESS_DEPRECATED_START
struct AllocatorImplWrapper {
AllocatorImplWrapper(const AllocatorImpl::Ptr& impl_) : impl{impl_} {}
void* allocate(const size_t bytes, const size_t alignment) {
return impl->allocate(bytes, alignment);
}
void deallocate(void* handle, const size_t bytes, const size_t alignment) {
impl->deallocate(handle, bytes, alignment);
}
bool is_equal(const AllocatorImplWrapper& other) const {
return impl->is_equal(*other.impl);
}
AllocatorImpl::Ptr impl;
};
Allocator::Allocator(const AllocatorImpl::Ptr& allocator_impl) : Allocator{AllocatorImplWrapper{allocator_impl}} {}
OPENVINO_SUPPRESS_DEPRECATED_END
Allocator::~Allocator() { Allocator::~Allocator() {
_impl = {}; _impl = {};
} }
Allocator::Allocator(const std::shared_ptr<AllocatorImpl>& impl, const std::shared_ptr<void>& so) Allocator::Allocator(const Allocator& other, const std::shared_ptr<void>& so) : _impl{other._impl}, _so{so} {
: _impl{impl},
_so{so} {
OPENVINO_ASSERT(_impl != nullptr, "Allocator was not initialized.");
}
Allocator::Allocator(const std::shared_ptr<AllocatorImpl>& impl) : _impl{impl} {
OPENVINO_ASSERT(_impl != nullptr, "Allocator was not initialized."); OPENVINO_ASSERT(_impl != nullptr, "Allocator was not initialized.");
} }

View File

@ -12,7 +12,7 @@
namespace InferenceEngine { namespace InferenceEngine {
struct BlobAllocator : public IAllocator { struct BlobAllocator : public IAllocator {
BlobAllocator(const std::shared_ptr<ov::AllocatorImpl>& impl) : _impl{impl} {} BlobAllocator(const ov::Allocator& impl) : _impl{impl} {}
void* lock(void* handle, LockOp) noexcept override { void* lock(void* handle, LockOp) noexcept override {
return handle; return handle;
@ -22,7 +22,7 @@ struct BlobAllocator : public IAllocator {
void* alloc(const size_t size) noexcept override { void* alloc(const size_t size) noexcept override {
try { try {
return size_map.emplace(_impl->allocate(size), size).first->first; return size_map.emplace(_impl.allocate(size), size).first->first;
} catch (...) { } catch (...) {
return nullptr; return nullptr;
} }
@ -32,24 +32,23 @@ struct BlobAllocator : public IAllocator {
try { try {
auto size = size_map.at(handle); auto size = size_map.at(handle);
size_map.erase(handle); size_map.erase(handle);
_impl->deallocate(handle, size); _impl.deallocate(handle, size);
return true; return true;
} catch (...) { } catch (...) {
return false; return false;
} }
} }
std::shared_ptr<ov::AllocatorImpl> _impl; ov::Allocator _impl;
std::unordered_map<void*, size_t> size_map; std::unordered_map<void*, size_t> size_map;
}; };
} // namespace InferenceEngine } // namespace InferenceEngine
namespace ov { namespace ov {
struct BlobAllocator : public runtime::AllocatorImpl { struct BlobAllocator {
BlobAllocator(const std::shared_ptr<ie::IAllocator>& impl = std::make_shared<ie::SystemMemoryAllocator>()) BlobAllocator() : _impl{std::make_shared<ie::SystemMemoryAllocator>()} {}
: _impl{impl} {}
void* allocate(const size_t bytes, const size_t alignment) override { void* allocate(const size_t bytes, const size_t alignment) {
OPENVINO_ASSERT(alignment == alignof(max_align_t), OPENVINO_ASSERT(alignment == alignof(max_align_t),
"Aligned deallocation is not implemented. alignment: ", "Aligned deallocation is not implemented. alignment: ",
alignment); alignment);
@ -58,7 +57,7 @@ struct BlobAllocator : public runtime::AllocatorImpl {
return handle; return handle;
} }
void deallocate(void* handle, const size_t bytes, const size_t alignment) override { void deallocate(void* handle, const size_t bytes, const size_t alignment) {
OPENVINO_ASSERT(bytes == 0, "Sized deallocation is not implemented. bytes: ", bytes); OPENVINO_ASSERT(bytes == 0, "Sized deallocation is not implemented. bytes: ", bytes);
OPENVINO_ASSERT(alignment == alignof(max_align_t), OPENVINO_ASSERT(alignment == alignof(max_align_t),
"Aligned deallocation is not implemented. alignment: ", "Aligned deallocation is not implemented. alignment: ",
@ -67,14 +66,10 @@ struct BlobAllocator : public runtime::AllocatorImpl {
OPENVINO_ASSERT(res != false, "Can not deallocate storage"); OPENVINO_ASSERT(res != false, "Can not deallocate storage");
} }
bool is_equal(const AllocatorImpl& other) const override { bool is_equal(const BlobAllocator& other) const {
auto other_blob_allocator = dynamic_cast<const BlobAllocator*>(&other); if (other._impl == _impl)
if (other_blob_allocator == nullptr)
return false;
if (other_blob_allocator->_impl == _impl)
return true; return true;
auto other_system_memory_allocator = auto other_system_memory_allocator = dynamic_cast<const ie::SystemMemoryAllocator*>(other._impl.get());
dynamic_cast<const ie::SystemMemoryAllocator*>(other_blob_allocator->_impl.get());
auto system_allocator = dynamic_cast<const ie::SystemMemoryAllocator*>(_impl.get()); auto system_allocator = dynamic_cast<const ie::SystemMemoryAllocator*>(_impl.get());
if (system_allocator != nullptr && other_system_memory_allocator != nullptr) if (system_allocator != nullptr && other_system_memory_allocator != nullptr)
return true; return true;

View File

@ -0,0 +1,281 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "openvino/runtime/itensor.hpp"
#include "dev/make_tensor.hpp"
#include "openvino/core/except.hpp"
#include "openvino/runtime/allocator.hpp"
#include "openvino/runtime/properties.hpp"
namespace ov {
ITensor::~ITensor() = default;
size_t ITensor::get_size() const {
return shape_size(get_shape());
}
size_t ITensor::get_byte_size() const {
return (get_size() * get_element_type().bitwidth() + 8 - 1) / 8;
}
/**
* @brief View tensor to external memory
* The tensor doesn't own the external memory
*/
class ViewTensor : public ITensor {
public:
ViewTensor(const element::Type element_type, const Shape& shape, void* ptr)
: m_element_type{element_type},
m_shape{shape},
m_capacity{shape},
m_ptr{ptr} {
OPENVINO_ASSERT(m_ptr != nullptr);
OPENVINO_ASSERT(m_element_type != element::undefined && m_element_type != element::dynamic);
update_strides();
}
void* data(const element::Type& element_type) const override {
if (element_type != element::undefined && element_type != element::dynamic) {
OPENVINO_ASSERT(element_type == get_element_type(),
"Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
}
return m_ptr;
}
const element::Type& get_element_type() const override {
return m_element_type;
}
const Shape& get_shape() const override {
return m_shape;
}
void set_shape(ov::Shape new_shape) override {
OPENVINO_ASSERT(shape_size(new_shape) <= ov::shape_size(m_capacity), "Could set new shape: ", new_shape);
m_shape = std::move(new_shape);
update_strides();
}
const Strides& get_strides() const override {
OPENVINO_ASSERT(m_element_type.bitwidth() >= 8,
"Could not get strides for types with bitwidths less then 8 bit. Tensor type: ",
m_element_type);
return m_strides;
}
protected:
void update_strides() {
if (m_element_type.bitwidth() < 8)
return;
auto& shape = get_shape();
m_strides.clear();
if (!shape.empty()) {
m_strides.resize(shape.size());
m_strides.back() = m_element_type.size();
std::copy(shape.rbegin(), shape.rend() - 1, m_strides.rbegin() + 1);
std::partial_sum(m_strides.rbegin(), m_strides.rend(), m_strides.rbegin(), std::multiplies<size_t>());
}
}
element::Type m_element_type;
Shape m_shape;
Shape m_capacity;
Strides m_strides;
void* m_ptr;
};
/**
* @brief View tensor on external memory with strides
*/
class StridedViewTensor : public ViewTensor {
public:
StridedViewTensor(const element::Type element_type, const Shape& shape, void* ptr, const Strides& strides)
: ViewTensor{element_type, shape, ptr} {
OPENVINO_ASSERT(
get_element_type().bitwidth() >= 8,
"Could not create strided access tensor for types with bitwidths less then 8 bit. Tensor type: ",
get_element_type());
// Save default strides
auto shape_strides = m_strides;
// Change strides
m_strides = strides;
OPENVINO_ASSERT(m_shape.size() == m_strides.size());
for (size_t i = 0; i < m_strides.size(); ++i) {
OPENVINO_ASSERT(shape_strides[i] <= m_strides[i],
"shape stride: ",
shape_strides[i],
", stride: ",
m_strides[i]);
OPENVINO_ASSERT((m_strides[i] % get_element_type().size()) == 0,
"shape stride: ",
shape_strides[i],
", stride: ",
m_strides[i]);
if (i) {
OPENVINO_ASSERT(m_strides[i - 1] >= m_strides[i] * shape[i],
"Strides: ",
m_strides,
" are incompatible with shapes: ",
m_shape);
}
}
}
void set_shape(ov::Shape new_shape) override {
OPENVINO_ASSERT(m_capacity.size() == new_shape.size(),
"Cannot set new shape: ",
new_shape,
" for tensor with strides! Shapes are not compatible.");
for (size_t i = 0; i < new_shape.size(); i++) {
OPENVINO_ASSERT(m_capacity[i] >= new_shape[i],
"Cannot set new shape: ",
new_shape,
" for tensor with strides! Dimension: ",
i,
" is not compatible.");
}
m_shape = std::move(new_shape);
}
};
/**
* @brief Creates view tensor on external memory
*
* @param element_type Tensor element type
* @param shape Tensor shape
* @param ptr pointer to external memoty
* @param byte_strides Tensor strides
*
* @return Shared pointer to tensor interface
*/
std::shared_ptr<ITensor> make_tensor(const element::Type element_type,
const Shape& shape,
void* ptr,
const Strides& byte_strides) {
return byte_strides.empty() ? std::make_shared<ViewTensor>(element_type, shape, ptr)
: std::make_shared<StridedViewTensor>(element_type, shape, ptr, byte_strides);
}
/**
* @brief Tensor with allocated memory
* Tensor owns the memory
*/
class AllocatedTensor : public ViewTensor {
public:
AllocatedTensor(const element::Type element_type, const Shape& shape, const Allocator& allocator)
: ViewTensor{element_type,
shape,
[&] {
OPENVINO_ASSERT(allocator, "Allocator was not initialized");
return const_cast<Allocator&>(allocator).allocate(element_type.size() * shape_size(shape));
}()},
m_allocator{allocator} {}
~AllocatedTensor() {
m_allocator.deallocate(m_ptr, get_byte_size());
}
void set_shape(ov::Shape new_shape) override {
auto old_byte_size = get_byte_size();
m_shape = std::move(new_shape);
if (get_byte_size() > old_byte_size) {
m_allocator.deallocate(m_ptr, old_byte_size);
m_ptr = m_allocator.allocate(get_byte_size());
}
update_strides();
}
private:
Allocator m_allocator;
};
/**
* @brief Creates allocated tensor
*
* @param element_type Tensor element type
* @param shape Tensor shape
* @param allocator Tensor allocator
*
* @return Shared pointer to tensor interface
*/
std::shared_ptr<ITensor> make_tensor(const element::Type element_type, const Shape& shape, const Allocator& allocator) {
return std::make_shared<AllocatedTensor>(element_type, shape, allocator);
}
/**
* @brief ROI tensor on other tensor
* ROI tensor holds the owner
*/
class RoiTensor : public ITensor {
public:
RoiTensor(const std::shared_ptr<ITensor>& owner, const Coordinate& begin, const Coordinate& end)
: m_owner{owner},
m_offsets{begin} {
OPENVINO_ASSERT(owner->get_element_type().bitwidth() >= 8,
"ROI Tensor for types with bitwidths less then 8 bit is not implemented. Tensor type: ",
owner->get_element_type());
auto owner_shape = owner->get_shape();
OPENVINO_ASSERT(owner_shape.size() == begin.size());
OPENVINO_ASSERT(begin.size() == end.size());
m_shape.resize(begin.size());
for (size_t i = 0; i < begin.size(); ++i) {
OPENVINO_ASSERT(begin[i] <= owner_shape[i]);
OPENVINO_ASSERT(end[i] <= owner_shape[i]);
m_shape[i] = end[i] - begin[i];
OPENVINO_ASSERT(m_shape[i] <= owner_shape[i]);
}
}
const element::Type& get_element_type() const override {
return m_owner->get_element_type();
}
const Strides& get_strides() const override {
return m_owner->get_strides();
}
const Shape& get_shape() const override {
return m_shape;
}
void set_shape(ov::Shape new_shape) override {
OPENVINO_THROW("Shapes cannot be changed for ROI Tensor");
}
void* data(const element::Type& element_type) const override {
auto owner_data = m_owner->data(element_type);
auto& strides = get_strides();
size_t byte_offset =
std::inner_product(m_offsets.begin(), m_offsets.end(), strides.begin(), static_cast<size_t>(0));
return static_cast<uint8_t*>(owner_data) + byte_offset;
}
private:
std::shared_ptr<ITensor> m_owner;
Coordinate m_offsets;
Shape m_shape;
};
/**
* @brief Creates ROI tensor
*
* @param other Tensor what owns the memory
* @param begin Begin coordinates
* @param end End coordinates
*
* @return Shared pointer to tensor interface
*/
std::shared_ptr<ITensor> make_tensor(const std::shared_ptr<ITensor>& other,
const Coordinate& begin,
const Coordinate& end) {
return std::make_shared<RoiTensor>(other, begin, end);
}
} // namespace ov

View File

@ -4,14 +4,14 @@
#include <numeric> #include <numeric>
#include "blob_factory.hpp" // IE private header #include "dev/make_tensor.hpp"
#include "ie_ngraph_utils.hpp" // IE private header
#include "openvino/core/except.hpp" #include "openvino/core/except.hpp"
#include "openvino/core/node_output.hpp"
#include "openvino/core/shape.hpp" #include "openvino/core/shape.hpp"
#include "openvino/core/strides.hpp" #include "openvino/core/strides.hpp"
#include "openvino/runtime/itensor.hpp"
#include "openvino/runtime/remote_tensor.hpp" #include "openvino/runtime/remote_tensor.hpp"
#include "openvino/runtime/tensor.hpp" #include "openvino/runtime/tensor.hpp"
#include "runtime/blob_allocator.hpp"
#include "shape_util.hpp" #include "shape_util.hpp"
namespace ov { namespace ov {
@ -32,70 +32,21 @@ Tensor::~Tensor() {
_impl = {}; _impl = {};
} }
Tensor::Tensor(const std::shared_ptr<ie::Blob>& impl, const std::vector<std::shared_ptr<void>>& so) Tensor::Tensor(const std::shared_ptr<ITensor>& impl, const std::vector<std::shared_ptr<void>>& so)
: _impl{impl}, : _impl{impl},
_so{so} { _so{so} {
OPENVINO_ASSERT(_impl != nullptr, "Tensor was not initialized."); OPENVINO_ASSERT(_impl != nullptr, "Tensor was not initialized.");
} }
Tensor::Tensor(const element::Type element_type, const Shape& shape, const Allocator& allocator) { Tensor::Tensor(const element::Type& element_type, const Shape& shape, const Allocator& allocator)
OPENVINO_ASSERT(allocator, "Allocator was not initialized"); : _impl{make_tensor(element_type, shape, allocator)} {}
auto allocator_impl = dynamic_cast<const BlobAllocator*>(allocator._impl.get());
auto blob_allocator =
(allocator_impl != nullptr) ? allocator_impl->_impl : std::make_shared<ie::BlobAllocator>(allocator._impl);
_impl = make_blob_with_precision(
{ie::details::convertPrecision(element_type), shape, ie::TensorDesc::getLayoutByDims(shape)},
blob_allocator);
_impl->allocate();
}
Tensor::Tensor(const element::Type element_type, const Shape& shape, void* host_ptr, const Strides& byte_strides) { Tensor::Tensor(const element::Type& element_type, const Shape& shape, void* host_ptr, const Strides& byte_strides)
ie::SizeVector blk_order(shape.size()); : _impl{make_tensor(element_type, shape, host_ptr, byte_strides)} {}
std::iota(blk_order.begin(), blk_order.end(), 0);
ie::SizeVector dim_offset(shape.size(), 0);
ie::SizeVector blk_strides;
if (byte_strides.empty()) {
blk_strides = ov::row_major_strides(shape);
} else {
blk_strides.resize(byte_strides.size());
std::transform(byte_strides.begin(),
byte_strides.end(),
blk_strides.begin(),
[&element_type](size_t byte_stride) {
OPENVINO_ASSERT(byte_stride % element_type.size() == 0,
"Limitation: Stride in bytes ",
byte_stride,
" should be divisible by size of element ",
element_type.size());
return byte_stride / element_type.size();
});
}
try { Tensor::Tensor(const Tensor& owner, const Coordinate& begin, const Coordinate& end)
_impl = make_blob_with_precision(ie::details::convertPrecision(element_type), : _impl{make_tensor(owner._impl, begin, end)},
ie::TensorDesc{ie::details::convertPrecision(element_type), _so{owner._so} {}
shape,
ie::BlockingDesc{shape, blk_order, 0, dim_offset, blk_strides}},
host_ptr);
} catch (const std::exception& ex) {
OPENVINO_THROW(ex.what());
} catch (...) {
OPENVINO_ASSERT(false, "Unexpected exception");
}
}
Tensor::Tensor(const Tensor& owner, const Coordinate& begin, const Coordinate& end) : _so{owner._so} {
OPENVINO_ASSERT(owner.get_element_type().bitwidth() >= 8,
"ROI Tensor for types with bitwidths less then 8 bit is not implemented. Tensor type: ",
owner.get_element_type());
try {
_impl = owner._impl->createROI(begin, end);
} catch (const std::exception& ex) {
OPENVINO_THROW(ex.what());
} catch (...) {
OPENVINO_ASSERT(false, "Unexpected exception");
}
}
Tensor::Tensor(const ov::Output<const ov::Node>& port, const Allocator& allocator) Tensor::Tensor(const ov::Output<const ov::Node>& port, const Allocator& allocator)
: Tensor(port.get_element_type(), : Tensor(port.get_element_type(),
@ -108,23 +59,16 @@ Tensor::Tensor(const ov::Output<const ov::Node>& port, void* host_ptr, const Str
host_ptr, host_ptr,
byte_strides) {} byte_strides) {}
element::Type Tensor::get_element_type() const { const element::Type& Tensor::get_element_type() const {
OV_TENSOR_STATEMENT(return ie::details::convertPrecision(_impl->getTensorDesc().getPrecision())); OV_TENSOR_STATEMENT(return _impl->get_element_type());
} }
void Tensor::set_shape(const ov::Shape& shape) { void Tensor::set_shape(const ov::Shape& shape) {
// WA for tensor conversion from host tensor with dynamic shape. OV_TENSOR_STATEMENT(_impl->set_shape(shape));
if (util::is_dynamic_shape(get_shape())) {
_impl = make_blob_with_precision(
{_impl->getTensorDesc().getPrecision(), shape, ie::TensorDesc::getLayoutByRank(shape.size())});
_impl->allocate();
} else {
OV_TENSOR_STATEMENT(_impl->setShape({shape.begin(), shape.end()}));
}
} }
Shape Tensor::get_shape() const { const Shape& Tensor::get_shape() const {
OV_TENSOR_STATEMENT({ return _impl->getTensorDesc().getBlockingDesc().getBlockDims(); }); OV_TENSOR_STATEMENT(return _impl->get_shape());
} }
void Tensor::copy_to(ov::Tensor& dst) const { void Tensor::copy_to(ov::Tensor& dst) const {
@ -258,55 +202,19 @@ void Tensor::copy_to(ov::Tensor& dst) const {
} }
Strides Tensor::get_strides() const { Strides Tensor::get_strides() const {
OPENVINO_ASSERT(get_element_type().bitwidth() >= 8, OV_TENSOR_STATEMENT(return _impl->get_strides(););
"Could not get strides for types with bitwidths less then 8 bit. Tensor type: ",
get_element_type());
OV_TENSOR_STATEMENT({
const auto& element_strides = _impl->getTensorDesc().getBlockingDesc().getStrides();
const size_t elem_size = get_element_type().size();
Strides byte_strides;
byte_strides.resize(element_strides.size());
std::transform(element_strides.begin(),
element_strides.end(),
byte_strides.begin(),
[&elem_size](size_t stride) {
return stride * elem_size;
});
return byte_strides;
});
} }
size_t Tensor::get_size() const { size_t Tensor::get_size() const {
OV_TENSOR_STATEMENT(return _impl->size()); OV_TENSOR_STATEMENT(return _impl->get_size());
} }
size_t Tensor::get_byte_size() const { size_t Tensor::get_byte_size() const {
OV_TENSOR_STATEMENT(return _impl->byteSize();); OV_TENSOR_STATEMENT(return _impl->get_byte_size(););
} }
void* Tensor::data(const element::Type element_type) const { void* Tensor::data(const element::Type& element_type) const {
OPENVINO_ASSERT(_impl != nullptr, "Tensor was not initialized."); OV_TENSOR_STATEMENT(return _impl->data(element_type));
#define TYPE_CHECK(TYPE) (dynamic_cast<const ie::TBlob<TYPE>*>(_impl.get()) != nullptr)
auto host_accesable_implementation = TYPE_CHECK(bool) || TYPE_CHECK(int8_t) || TYPE_CHECK(uint8_t) ||
TYPE_CHECK(int16_t) || TYPE_CHECK(uint16_t) || TYPE_CHECK(int32_t) ||
TYPE_CHECK(uint32_t) || TYPE_CHECK(int64_t) || TYPE_CHECK(uint64_t) ||
TYPE_CHECK(float) || TYPE_CHECK(double);
#undef TYPE_CHECK
OPENVINO_ASSERT(host_accesable_implementation, "Tensor implementation type dose not contains host accessable data");
if (element_type != element::undefined) {
OPENVINO_ASSERT(element_type == get_element_type(),
"Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
}
// since we don't use byte offsets, we need to explicitly multiply by element_size
auto byte_offset = _impl->getTensorDesc().getBlockingDesc().getOffsetPadding() * get_element_type().size();
OPENVINO_ASSERT((get_element_type().bitwidth() >= 8) || (byte_offset == 0),
"ROI access for types with bitwidths less then 8 bit is not implemented. Tensor type: ",
get_element_type());
OV_TENSOR_STATEMENT(
{ return byte_offset + InferenceEngine::as<InferenceEngine::MemoryBlob>(_impl)->rmap().as<uint8_t*>(); });
} }
bool Tensor::operator!() const noexcept { bool Tensor::operator!() const noexcept {

View File

@ -25,18 +25,18 @@ TEST_F(OVDefaultAllocatorTest, canAllocateAndDeallocate) {
ASSERT_NO_THROW(allocator.deallocate(ptr)); ASSERT_NO_THROW(allocator.deallocate(ptr));
} }
TEST_F(OVDefaultAllocatorTest, alignedAllocationIsNotImplemented) { TEST_F(OVDefaultAllocatorTest, alignedAllocationNotThrow) {
ov::Allocator allocator; ov::Allocator allocator;
ASSERT_THROW(allocator.allocate(64, 64), ov::Exception); ASSERT_NO_THROW(allocator.allocate(64, 64));
} }
TEST_F(OVDefaultAllocatorTest, sizedAndAlignedDeallocationAreNotImplemented) { TEST_F(OVDefaultAllocatorTest, sizedAndAlignedDeallocationNotThrow) {
ov::Allocator allocator; ov::Allocator allocator;
void* ptr = nullptr; void* ptr = nullptr;
ASSERT_NO_THROW(ptr = allocator.allocate(64)); ASSERT_NO_THROW(ptr = allocator.allocate(64));
ASSERT_THROW(allocator.deallocate(ptr, 64), ov::Exception); ASSERT_NO_THROW(allocator.deallocate(ptr, 64));
ASSERT_THROW(allocator.deallocate(ptr, 0, 64), ov::Exception); ASSERT_NO_THROW(ptr = allocator.allocate(64, 64));
ASSERT_NO_THROW(allocator.deallocate(ptr)); ASSERT_NO_THROW(allocator.deallocate(ptr, 64, 64));
} }
TEST_F(OVDefaultAllocatorTest, defaultAllocatorsAreEqual) { TEST_F(OVDefaultAllocatorTest, defaultAllocatorsAreEqual) {

View File

@ -87,16 +87,18 @@ TEST_F(OVTensorTest, operators) {
ASSERT_TRUE(!t); ASSERT_TRUE(!t);
} }
class OVMockAllocator : public ov::AllocatorImpl { OPENVINO_SUPPRESS_DEPRECATED_START
class OVMockAllocatorImpl : public ov::AllocatorImpl {
public: public:
MOCK_METHOD(void*, allocate, (size_t, size_t), ()); MOCK_METHOD(void*, allocate, (size_t, size_t), ());
MOCK_METHOD(void, deallocate, (void*, size_t, size_t), ()); // NOLINT(readability/casting) MOCK_METHOD(void, deallocate, (void*, size_t, size_t), ()); // NOLINT(readability/casting)
MOCK_METHOD(bool, is_equal, (const ov::AllocatorImpl&), (const, noexcept)); // NOLINT(readability/casting) MOCK_METHOD(bool, is_equal, (const ov::AllocatorImpl&), (const, noexcept)); // NOLINT(readability/casting)
}; };
TEST_F(OVTensorTest, canCreateTensorUsingMockAllocator) { OPENVINO_SUPPRESS_DEPRECATED_START
TEST_F(OVTensorTest, canCreateTensorUsingMockAllocatorImpl) {
ov::Shape shape = {1, 2, 3}; ov::Shape shape = {1, 2, 3};
auto allocator = std::make_shared<OVMockAllocator>(); auto allocator = std::make_shared<OVMockAllocatorImpl>();
EXPECT_CALL(*allocator, allocate(::testing::_, ::testing::_)) EXPECT_CALL(*allocator, allocate(::testing::_, ::testing::_))
.WillRepeatedly(testing::Return(reinterpret_cast<void*>(1))); .WillRepeatedly(testing::Return(reinterpret_cast<void*>(1)));
@ -104,6 +106,40 @@ TEST_F(OVTensorTest, canCreateTensorUsingMockAllocator) {
{ ov::Tensor t{ov::element::f32, shape, ov::Allocator{allocator}}; } { ov::Tensor t{ov::element::f32, shape, ov::Allocator{allocator}}; }
} }
OPENVINO_SUPPRESS_DEPRECATED_END
struct OVMockAllocator {
struct Impl {
MOCK_METHOD(void*, allocate, (size_t, size_t), ());
MOCK_METHOD(void, deallocate, (void*, size_t, size_t), ());
MOCK_METHOD(bool, is_equal, (const Impl&), (const, noexcept));
};
OVMockAllocator() : impl{std::make_shared<Impl>()} {}
void* allocate(size_t b, size_t a) {
return impl->allocate(b, a);
}
void deallocate(void* ptr, size_t b, size_t a) {
impl->deallocate(ptr, b, a);
}
bool is_equal(const OVMockAllocator& other) const {
return impl->is_equal(*other.impl);
}
std::shared_ptr<Impl> impl;
};
TEST_F(OVTensorTest, canCreateTensorUsingMockAllocator) {
ov::Shape shape = {1, 2, 3};
OVMockAllocator allocator;
EXPECT_CALL(*allocator.impl, allocate(::testing::_, ::testing::_))
.WillRepeatedly(testing::Return(reinterpret_cast<void*>(1)));
EXPECT_CALL(*allocator.impl, deallocate(::testing::_, ::testing::_, ::testing::_)).Times(1);
{ ov::Tensor t{ov::element::f32, shape, allocator}; }
}
TEST_F(OVTensorTest, canAccessExternalData) { TEST_F(OVTensorTest, canAccessExternalData) {
ov::Shape shape = {1, 1, 3}; ov::Shape shape = {1, 1, 3};
@ -235,7 +271,7 @@ TEST_F(OVTensorTest, canSetShapeOfSameSizeOnPreallocatedMemory) {
ASSERT_NO_THROW(t.set_shape(newShape)); ASSERT_NO_THROW(t.set_shape(newShape));
} }
TEST_F(OVTensorTest, DISABLED_canSetShapeOfOriginalSizeAfterDecreasingOnPreallocatedMemory) { TEST_F(OVTensorTest, canSetShapeOfOriginalSizeAfterDecreasingOnPreallocatedMemory) {
float data[4 * 5 * 6 * 2]; float data[4 * 5 * 6 * 2];
ov::Tensor t{ov::element::f32, {4, 5, 6}, data}; ov::Tensor t{ov::element::f32, {4, 5, 6}, data};
const ov::Shape smallerShape({1, 2, 3}); const ov::Shape smallerShape({1, 2, 3});
@ -245,6 +281,16 @@ TEST_F(OVTensorTest, DISABLED_canSetShapeOfOriginalSizeAfterDecreasingOnPrealloc
ASSERT_NO_THROW(t.set_shape(originalShape)); ASSERT_NO_THROW(t.set_shape(originalShape));
} }
TEST_F(OVTensorTest, canChangeShapeOnStridedTensor) {
float data[64 * 4];
ov::Tensor t{ov::element::f32, {4, 2, 2}, data, {64, 16, 4}};
const ov::Shape incorrect_shape({2, 4, 2});
const ov::Shape correct_shape({1, 1, 2});
ASSERT_THROW(t.set_shape(incorrect_shape), ov::Exception);
ASSERT_NO_THROW(t.set_shape(correct_shape));
}
TEST_F(OVTensorTest, makeRangeRoiTensor) { TEST_F(OVTensorTest, makeRangeRoiTensor) {
ov::Tensor t{ov::element::i32, {1, 3, 6, 5}}; // RGBp picture of size (WxH) = 5x6 ov::Tensor t{ov::element::i32, {1, 3, 6, 5}}; // RGBp picture of size (WxH) = 5x6
ov::Tensor roi_tensor{t, {0, 0, 1, 2}, {1, 3, 5, 4}}; ov::Tensor roi_tensor{t, {0, 0, 1, 2}, {1, 3, 5, 4}};

View File

@ -0,0 +1,37 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
/**
* @brief OpenVINO Runtime IRemoteTensor interface
* @file openvino/runtime/iremote_tensor.hpp
*/
#pragma once
#include "openvino/core/except.hpp"
#include "openvino/runtime/common.hpp"
#include "openvino/runtime/itensor.hpp"
namespace ov {
class OPENVINO_RUNTIME_API IRemoteTensor : public ITensor {
public:
void* data(const element::Type& type = {}) const final {
OPENVINO_NOT_IMPLEMENTED;
}
~IRemoteTensor() override;
/**
* @brief Returns additional information associated with tensor
* @return Map of property names to properties
*/
virtual const AnyMap& get_properties() const = 0;
/**
* @brief Returns device name
* @return Device name
*/
virtual const std::string& get_device_name() const = 0;
};
} // namespace ov

View File

@ -192,7 +192,7 @@ public:
* *
* @param dims new shape * @param dims new shape
*/ */
void setShape(const SizeVector& dims); virtual void setShape(const SizeVector& dims);
/** /**
* @deprecated Cast to MemoryBlob and use new wlock/rwlock API instead. * @deprecated Cast to MemoryBlob and use new wlock/rwlock API instead.

View File

@ -7,9 +7,11 @@
#include <exception> #include <exception>
#include "any_copy.hpp" #include "any_copy.hpp"
#include "dev/make_tensor.hpp"
#include "ie_ngraph_utils.hpp" #include "ie_ngraph_utils.hpp"
#include "ie_remote_blob.hpp" #include "ie_remote_blob.hpp"
#include "openvino/core/except.hpp" #include "openvino/core/except.hpp"
#include "openvino/runtime/itensor.hpp"
#include "openvino/runtime/remote_context.hpp" #include "openvino/runtime/remote_context.hpp"
#define OV_REMOTE_CONTEXT_STATEMENT(...) \ #define OV_REMOTE_CONTEXT_STATEMENT(...) \
@ -67,7 +69,7 @@ RemoteTensor RemoteContext::create_tensor(const element::Type& type, const Shape
{ie::details::convertPrecision(type), shape, ie::TensorDesc::getLayoutByRank(shape.size())}, {ie::details::convertPrecision(type), shape, ie::TensorDesc::getLayoutByRank(shape.size())},
params); params);
blob->allocate(); blob->allocate();
return {blob, {_so}}; return {ov::make_tensor(blob), {_so}};
}); });
} }
@ -76,7 +78,7 @@ Tensor RemoteContext::create_host_tensor(const element::Type element_type, const
auto blob = _impl->CreateHostBlob( auto blob = _impl->CreateHostBlob(
{ie::details::convertPrecision(element_type), shape, ie::TensorDesc::getLayoutByRank(shape.size())}); {ie::details::convertPrecision(element_type), shape, ie::TensorDesc::getLayoutByRank(shape.size())});
blob->allocate(); blob->allocate();
return {blob, {_so}}; return {ov::make_tensor(blob), {_so}};
}); });
} }

View File

@ -13,6 +13,7 @@
#include "cpp_interfaces/interface/ie_iexecutable_network_internal.hpp" #include "cpp_interfaces/interface/ie_iexecutable_network_internal.hpp"
#include "cpp_interfaces/interface/ie_iplugin_internal.hpp" #include "cpp_interfaces/interface/ie_iplugin_internal.hpp"
#include "cpp_interfaces/interface/ie_ivariable_state_internal.hpp" #include "cpp_interfaces/interface/ie_ivariable_state_internal.hpp"
#include "dev/make_tensor.hpp"
#include "icompiled_model_wrapper.hpp" #include "icompiled_model_wrapper.hpp"
#include "ie_blob.h" #include "ie_blob.h"
#include "ie_common.h" #include "ie_common.h"
@ -30,6 +31,7 @@
#include "openvino/runtime/icompiled_model.hpp" #include "openvino/runtime/icompiled_model.hpp"
#include "openvino/runtime/iinfer_request.hpp" #include "openvino/runtime/iinfer_request.hpp"
#include "openvino/runtime/iplugin.hpp" #include "openvino/runtime/iplugin.hpp"
#include "openvino/runtime/itensor.hpp"
#include "openvino/runtime/ivariable_state.hpp" #include "openvino/runtime/ivariable_state.hpp"
#include "openvino/runtime/profiling_info.hpp" #include "openvino/runtime/profiling_info.hpp"
#include "openvino/runtime/remote_context.hpp" #include "openvino/runtime/remote_context.hpp"
@ -206,11 +208,11 @@ public:
} }
void SetState(const InferenceEngine::Blob::Ptr& newState) override { void SetState(const InferenceEngine::Blob::Ptr& newState) override {
m_state->set_state(ov::Tensor(newState, {})); m_state->set_state(ov::Tensor(ov::make_tensor(newState), {}));
} }
InferenceEngine::Blob::CPtr GetState() const override { InferenceEngine::Blob::CPtr GetState() const override {
return m_state->get_state()._impl; return tensor_to_blob(m_state->get_state()._impl);
} }
}; };
@ -499,7 +501,7 @@ public:
void SetBlob(const std::string& name, const InferenceEngine::Blob::Ptr& data) override { void SetBlob(const std::string& name, const InferenceEngine::Blob::Ptr& data) override {
try { try {
m_request->set_tensor(find_port(name), ov::Tensor{data, {}}); m_request->set_tensor(find_port(name), ov::Tensor{ov::make_tensor(data), {}});
} catch (const ov::Exception& ex) { } catch (const ov::Exception& ex) {
const std::string what = ex.what(); const std::string what = ex.what();
if (what.find("Failed to set tensor") != std::string::npos) { if (what.find("Failed to set tensor") != std::string::npos) {
@ -513,7 +515,7 @@ public:
try { try {
std::vector<ov::Tensor> tensors; std::vector<ov::Tensor> tensors;
for (const auto& blob : blobs) { for (const auto& blob : blobs) {
tensors.emplace_back(ov::Tensor{blob, {}}); tensors.emplace_back(ov::Tensor{ov::make_tensor(blob), {}});
} }
m_request->set_tensors(find_port(name), tensors); m_request->set_tensors(find_port(name), tensors);
} catch (const ov::Exception& ex) { } catch (const ov::Exception& ex) {
@ -522,14 +524,14 @@ public:
} }
InferenceEngine::Blob::Ptr GetBlob(const std::string& name) override { InferenceEngine::Blob::Ptr GetBlob(const std::string& name) override {
return m_request->get_tensor(find_port(name))._impl; return tensor_to_blob(m_request->get_tensor(find_port(name))._impl);
} }
InferenceEngine::BatchedBlob::Ptr GetBlobs(const std::string& name) override { InferenceEngine::BatchedBlob::Ptr GetBlobs(const std::string& name) override {
auto tensors = m_request->get_tensors(find_port(name)); auto tensors = m_request->get_tensors(find_port(name));
std::vector<InferenceEngine::Blob::Ptr> blobs; std::vector<InferenceEngine::Blob::Ptr> blobs;
for (const auto& tensor : tensors) { for (const auto& tensor : tensors) {
blobs.emplace_back(tensor._impl); blobs.emplace_back(tensor_to_blob(tensor._impl));
} }
return std::make_shared<InferenceEngine::BatchedBlob>(blobs); return std::make_shared<InferenceEngine::BatchedBlob>(blobs);
} }
@ -604,11 +606,12 @@ public:
} }
void set_state(const ov::Tensor& state) override { void set_state(const ov::Tensor& state) override {
m_state->SetState(state._impl); m_state->SetState(ov::tensor_to_blob(state._impl));
} }
const ov::Tensor& get_state() const override { const ov::Tensor& get_state() const override {
m_converted_state = ov::Tensor(std::const_pointer_cast<InferenceEngine::Blob>(m_state->GetState()), {}); m_converted_state =
ov::Tensor(ov::make_tensor(std::const_pointer_cast<InferenceEngine::Blob>(m_state->GetState())), {});
return m_converted_state; return m_converted_state;
} }
}; };
@ -706,11 +709,11 @@ public:
name, name,
"'"); "'");
auto blob = m_request->GetBlob(name); auto blob = m_request->GetBlob(name);
ov::Tensor tensor = {blob, {m_request->getPointerToSo()}}; ov::Tensor tensor = {ov::make_tensor(blob), {m_request->getPointerToSo()}};
return tensor; return tensor;
} }
void set_tensor(const ov::Output<const ov::Node>& port, const ov::Tensor& tensor) override { void set_tensor(const ov::Output<const ov::Node>& port, const ov::Tensor& tensor) override {
m_request->SetBlob(get_legacy_name_from_port(port), tensor._impl); m_request->SetBlob(get_legacy_name_from_port(port), ov::tensor_to_blob(tensor._impl));
} }
std::vector<ov::Tensor> get_tensors(const ov::Output<const ov::Node>& port) const override { std::vector<ov::Tensor> get_tensors(const ov::Output<const ov::Node>& port) const override {
@ -719,14 +722,14 @@ public:
if (!blobs) if (!blobs)
return ret; return ret;
for (size_t i = 0; i < blobs->size(); i++) { for (size_t i = 0; i < blobs->size(); i++) {
ret.emplace_back(ov::Tensor{blobs->getBlob(i), {m_request->getPointerToSo()}}); ret.emplace_back(ov::Tensor{ov::make_tensor(blobs->getBlob(i)), {m_request->getPointerToSo()}});
} }
return ret; return ret;
} }
void set_tensors(const ov::Output<const ov::Node>& port, const std::vector<ov::Tensor>& tensors) override { void set_tensors(const ov::Output<const ov::Node>& port, const std::vector<ov::Tensor>& tensors) override {
std::vector<InferenceEngine::Blob::Ptr> blobs; std::vector<InferenceEngine::Blob::Ptr> blobs;
for (const auto& tensor : tensors) { for (const auto& tensor : tensors) {
blobs.emplace_back(tensor._impl); blobs.emplace_back(ov::tensor_to_blob(tensor._impl));
} }
m_request->SetBlobs(get_legacy_name_from_port(port), blobs); m_request->SetBlobs(get_legacy_name_from_port(port), blobs);
} }

View File

@ -13,6 +13,7 @@
#include "cpp_interfaces/interface/ie_internal_plugin_config.hpp" #include "cpp_interfaces/interface/ie_internal_plugin_config.hpp"
#include "cpp_interfaces/interface/ie_iplugin_internal.hpp" #include "cpp_interfaces/interface/ie_iplugin_internal.hpp"
#include "dev/converter_utils.hpp" #include "dev/converter_utils.hpp"
#include "dev/make_tensor.hpp"
#include "file_utils.h" #include "file_utils.h"
#include "ie_itt.hpp" #include "ie_itt.hpp"
#include "ie_network_reader.hpp" #include "ie_network_reader.hpp"
@ -27,6 +28,7 @@
#include "openvino/core/version.hpp" #include "openvino/core/version.hpp"
#include "openvino/pass/manager.hpp" #include "openvino/pass/manager.hpp"
#include "openvino/runtime/icompiled_model.hpp" #include "openvino/runtime/icompiled_model.hpp"
#include "openvino/runtime/itensor.hpp"
#include "openvino/runtime/remote_context.hpp" #include "openvino/runtime/remote_context.hpp"
#include "openvino/runtime/threading/executor_manager.hpp" #include "openvino/runtime/threading/executor_manager.hpp"
#include "openvino/util/common_util.hpp" #include "openvino/util/common_util.hpp"
@ -1097,7 +1099,7 @@ std::shared_ptr<ov::Model> ov::CoreImpl::read_model(const std::string& model,
bool frontendMode) const { bool frontendMode) const {
InferenceEngine::Blob::Ptr blob; InferenceEngine::Blob::Ptr blob;
if (weights) { if (weights) {
blob = weights._impl; blob = tensor_to_blob(weights._impl);
} }
OV_ITT_SCOPE(FIRST_INFERENCE, ov::itt::domains::IE_RT, "CoreImpl::read_model from memory"); OV_ITT_SCOPE(FIRST_INFERENCE, ov::itt::domains::IE_RT, "CoreImpl::read_model from memory");
return ReadNetwork(model, blob, frontendMode).getFunction(); return ReadNetwork(model, blob, frontendMode).getFunction();

View File

@ -10,6 +10,7 @@
#include "cpp_interfaces/interface/ie_internal_plugin_config.hpp" #include "cpp_interfaces/interface/ie_internal_plugin_config.hpp"
#include "cpp_interfaces/interface/ie_iplugin_internal.hpp" #include "cpp_interfaces/interface/ie_iplugin_internal.hpp"
#include "dev/converter_utils.hpp" #include "dev/converter_utils.hpp"
#include "dev/make_tensor.hpp"
#include "ie_itt.hpp" #include "ie_itt.hpp"
#include "ie_network_reader.hpp" #include "ie_network_reader.hpp"
#include "iplugin_wrapper.hpp" #include "iplugin_wrapper.hpp"
@ -17,6 +18,7 @@
#include "ngraph/pass/constant_folding.hpp" #include "ngraph/pass/constant_folding.hpp"
#include "openvino/itt.hpp" #include "openvino/itt.hpp"
#include "openvino/runtime/icompiled_model.hpp" #include "openvino/runtime/icompiled_model.hpp"
#include "openvino/runtime/itensor.hpp"
#include "openvino/util/common_util.hpp" #include "openvino/util/common_util.hpp"
bool ov::CoreImpl::isNewAPI() const { bool ov::CoreImpl::isNewAPI() const {
@ -113,10 +115,11 @@ InferenceEngine::SoExecutableNetworkInternal ov::CoreImpl::LoadNetwork(
const std::function<void(const InferenceEngine::CNNNetwork&)>& val) { const std::function<void(const InferenceEngine::CNNNetwork&)>& val) {
OV_ITT_SCOPE(FIRST_INFERENCE, InferenceEngine::itt::domains::IE_LT, "Core::LoadNetwork::Memory"); OV_ITT_SCOPE(FIRST_INFERENCE, InferenceEngine::itt::domains::IE_LT, "Core::LoadNetwork::Memory");
auto compiled_model = compile_model(modelStr, auto compiled_model =
ov::Tensor{std::const_pointer_cast<InferenceEngine::Blob>(weights), {}}, compile_model(modelStr,
deviceName, ov::Tensor{ov::make_tensor(std::const_pointer_cast<InferenceEngine::Blob>(weights)), {}},
ov::any_copy(config)); deviceName,
ov::any_copy(config));
return {ov::legacy_convert::convert_compiled_model(compiled_model._ptr), compiled_model._so}; return {ov::legacy_convert::convert_compiled_model(compiled_model._ptr), compiled_model._so};
} }

View File

@ -0,0 +1,351 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "openvino/runtime/iremote_tensor.hpp"
#include <memory>
#include "dev/make_tensor.hpp"
#include "ie_blob.h"
#include "ie_ngraph_utils.hpp"
#include "ie_remote_blob.hpp"
#include "openvino/runtime/properties.hpp"
namespace ov {
IRemoteTensor::~IRemoteTensor() = default;
/**
* @brief Tensor what contains InferenceEngine::Blob inside
* Blob owns the memory
*/
class BlobTensor : public ITensor {
mutable element::Type m_type;
mutable Shape m_shape;
mutable Strides m_strides;
public:
std::shared_ptr<ie::Blob> blob;
BlobTensor(const InferenceEngine::Blob::Ptr& blob) : blob{blob} {
auto remote_impl = dynamic_cast<InferenceEngine::RemoteBlob*>(blob.get());
OPENVINO_ASSERT(!remote_impl);
OPENVINO_ASSERT(blob);
m_shape = blob->getTensorDesc().getBlockingDesc().getBlockDims();
}
const element::Type& get_element_type() const override {
m_type = InferenceEngine::details::convertPrecision(blob->getTensorDesc().getPrecision());
return m_type;
}
void set_shape(ov::Shape shape) override {
blob->setShape({shape.begin(), shape.end()});
}
const Shape& get_shape() const override {
m_shape = blob->getTensorDesc().getBlockingDesc().getBlockDims();
return m_shape;
}
const Strides& get_strides() const override {
OPENVINO_ASSERT(get_element_type().bitwidth() >= 8,
"Could not get strides for types with bitwidths less then 8 bit. Tensor type: ",
get_element_type());
const auto& element_strides = blob->getTensorDesc().getBlockingDesc().getStrides();
const size_t elem_size = get_element_type().size();
m_strides.clear();
m_strides.resize(element_strides.size());
std::transform(element_strides.begin(), element_strides.end(), m_strides.begin(), [&elem_size](size_t stride) {
return stride * elem_size;
});
return m_strides;
}
size_t get_size() const override {
return blob->size();
}
size_t get_byte_size() const override {
return blob->byteSize();
}
void* data(const element::Type& element_type) const override {
OPENVINO_ASSERT(blob != nullptr, "Tensor was not initialized.");
#define TYPE_CHECK(TYPE) (dynamic_cast<const ie::TBlob<TYPE>*>(blob.get()) != nullptr)
auto host_accesable_implementation = TYPE_CHECK(bool) || TYPE_CHECK(int8_t) || TYPE_CHECK(uint8_t) ||
TYPE_CHECK(int16_t) || TYPE_CHECK(uint16_t) || TYPE_CHECK(int32_t) ||
TYPE_CHECK(uint32_t) || TYPE_CHECK(int64_t) || TYPE_CHECK(uint64_t) ||
TYPE_CHECK(float) || TYPE_CHECK(double);
#undef TYPE_CHECK
OPENVINO_ASSERT(host_accesable_implementation,
"Tensor implementation type dose not contains host accessable data");
if (element_type != element::undefined) {
OPENVINO_ASSERT(element_type == get_element_type(),
"Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
}
// since we don't use byte offsets, we need to explicitly multiply by element_size
auto byte_offset = blob->getTensorDesc().getBlockingDesc().getOffsetPadding() * get_element_type().size();
OPENVINO_ASSERT((get_element_type().bitwidth() >= 8) || (byte_offset == 0),
"ROI access for types with bitwidths less then 8 bit is not implemented. Tensor type: ",
get_element_type());
return byte_offset + InferenceEngine::as<InferenceEngine::MemoryBlob>(blob)->rmap().as<uint8_t*>();
}
};
/**
* @brief Tensor what contains InferenceEngine::RemoteBlob inside
* Blob owns the memory
*/
class RemoteBlobTensor : public IRemoteTensor {
mutable element::Type m_type;
mutable Shape m_shape;
mutable Strides m_strides;
mutable ov::AnyMap m_properties;
mutable std::string m_dev_name;
public:
std::shared_ptr<ie::RemoteBlob> blob;
RemoteBlobTensor(const InferenceEngine::RemoteBlob::Ptr& blob) : blob{blob} {
OPENVINO_ASSERT(blob);
m_shape = blob->getTensorDesc().getBlockingDesc().getBlockDims();
}
const element::Type& get_element_type() const override {
m_type = InferenceEngine::details::convertPrecision(blob->getTensorDesc().getPrecision());
return m_type;
}
void set_shape(ov::Shape shape) override {
blob->setShape({shape.begin(), shape.end()});
}
const Shape& get_shape() const override {
m_shape = blob->getTensorDesc().getBlockingDesc().getBlockDims();
return m_shape;
}
const Strides& get_strides() const override {
OPENVINO_ASSERT(get_element_type().bitwidth() >= 8,
"Could not get strides for types with bitwidths less then 8 bit. Tensor type: ",
get_element_type());
const auto& element_strides = blob->getTensorDesc().getBlockingDesc().getStrides();
const size_t elem_size = get_element_type().size();
m_strides.clear();
m_strides.resize(element_strides.size());
std::transform(element_strides.begin(), element_strides.end(), m_strides.begin(), [&elem_size](size_t stride) {
return stride * elem_size;
});
return m_strides;
}
size_t get_size() const override {
return blob->size();
}
size_t get_byte_size() const override {
return blob->byteSize();
}
const AnyMap& get_properties() const override {
m_properties = blob->getParams();
return m_properties;
}
const std::string& get_device_name() const override {
m_dev_name = blob->getDeviceName();
return m_dev_name;
}
};
/**
* @brief Create InferenceEngine::RemoteBlob from the Tensor
*/
class TensorRemoteBlob : public ie::RemoteBlob {
public:
TensorRemoteBlob(const std::shared_ptr<ITensor>& tensor)
: ie::RemoteBlob{ie::TensorDesc{ie::details::convertPrecision(tensor->get_element_type()),
tensor->get_shape(),
ie::TensorDesc::getLayoutByRank(tensor->get_shape().size())}},
tensor{std::dynamic_pointer_cast<ov::IRemoteTensor>(tensor)} {
OPENVINO_ASSERT(this->tensor);
}
AnyMap getParams() const override {
return tensor->get_properties();
}
std::string getDeviceName() const noexcept override {
try {
return tensor->get_device_name();
} catch (...) {
return {};
}
}
std::shared_ptr<ie::RemoteContext> getContext() const noexcept override {
return {};
}
void allocate() noexcept override {}
bool deallocate() noexcept override {
return true;
}
ie::LockedMemory<void> buffer() noexcept override {
return {nullptr, nullptr, 0};
}
ie::LockedMemory<const void> cbuffer() const noexcept override {
return {nullptr, nullptr, 0};
}
ie::LockedMemory<void> rwmap() noexcept override {
return {nullptr, nullptr, 0};
}
ie::LockedMemory<const void> rmap() const noexcept override {
return {nullptr, nullptr, 0};
}
ie::LockedMemory<void> wmap() noexcept override {
return {nullptr, nullptr, 0};
}
const std::shared_ptr<ie::IAllocator>& getAllocator() const noexcept override {
return m_allocator;
}
void* getHandle() const noexcept override {
return nullptr;
}
std::shared_ptr<IRemoteTensor> tensor;
private:
std::shared_ptr<ie::IAllocator> m_allocator;
};
/**
* @brief Create InferenceEngine::TBlob<T> from the tensor
*
* @tparam T Blob data type
*/
template <typename T>
class TensorMemoryBlob : public ie::TBlob<T> {
public:
~TensorMemoryBlob() override = default;
explicit TensorMemoryBlob(const std::shared_ptr<ITensor>& tensor_) try : ie
::TBlob<T>{[&] {
auto element_type = tensor_->get_element_type();
auto shape = tensor_->get_shape();
ie::SizeVector blk_order(shape.size());
std::iota(blk_order.begin(), blk_order.end(), 0);
ie::SizeVector dim_offset(shape.size(), 0);
ie::SizeVector blk_strides;
auto byte_strides = element_type.bitwidth() >= 8 ? tensor_->get_strides() : Strides{};
if (byte_strides.empty()) {
blk_strides = ov::row_major_strides(shape);
} else {
blk_strides.resize(byte_strides.size());
std::transform(byte_strides.begin(),
byte_strides.end(),
blk_strides.begin(),
[&element_type](size_t byte_stride) {
OPENVINO_ASSERT(byte_stride % element_type.size() == 0,
"Limitation: Stride in bytes ",
byte_stride,
" should be divisible by size of element ",
element_type.size());
return byte_stride / element_type.size();
});
}
return ie::TensorDesc{ie::details::convertPrecision(element_type),
shape,
ie::BlockingDesc{shape, blk_order, 0, dim_offset, blk_strides}};
}(),
static_cast<T*>(tensor_->data()),
tensor_->get_byte_size()},
tensor{tensor_} {
OPENVINO_ASSERT(!std::dynamic_pointer_cast<ov::IRemoteTensor>(tensor));
}
catch (const std::exception& ex) {
throw ov::Exception(ex.what());
}
void setShape(const ie::SizeVector& dims) override {
tensor->set_shape(dims);
ie::TBlob<T>::setShape(dims);
}
std::shared_ptr<ITensor> tensor;
};
std::shared_ptr<ITensor> make_tensor(const std::shared_ptr<ie::Blob>& blob) {
#define ELSE_IF(type) \
else if (auto tblob = dynamic_cast<const TensorMemoryBlob<type>*>(blob.get())) { \
return tblob->tensor; \
}
if (blob == nullptr) {
return {};
} else if (auto remote_blob = std::dynamic_pointer_cast<TensorRemoteBlob>(blob)) {
return remote_blob->tensor;
} else if (auto remote_blob = std::dynamic_pointer_cast<InferenceEngine::RemoteBlob>(blob)) {
return std::make_shared<RemoteBlobTensor>(remote_blob);
}
ELSE_IF(float)
ELSE_IF(double)
ELSE_IF(int8_t)
ELSE_IF(int8_t)
ELSE_IF(int16_t)
ELSE_IF(int32_t)
ELSE_IF(int64_t)
ELSE_IF(uint8_t)
ELSE_IF(uint8_t)
ELSE_IF(uint16_t)
ELSE_IF(uint32_t)
ELSE_IF(uint64_t)
ELSE_IF(int8_t)
ELSE_IF(bool) else {
return std::make_shared<BlobTensor>(blob);
}
#undef IF
}
ie::Blob::Ptr tensor_to_blob(const std::shared_ptr<ITensor>& tensor) {
if (tensor == nullptr) {
return {};
} else if (auto blob_tensor = std::dynamic_pointer_cast<BlobTensor>(tensor)) {
return blob_tensor->blob;
} else if (auto blob_tensor = std::dynamic_pointer_cast<RemoteBlobTensor>(tensor)) {
return blob_tensor->blob;
} else if (auto blob_tensor = dynamic_cast<const BlobTensor*>(tensor.get())) {
return blob_tensor->blob;
} else if (std::dynamic_pointer_cast<ov::IRemoteTensor>(tensor)) {
return std::make_shared<TensorRemoteBlob>(tensor);
} else {
#define CASE(precision, T) \
case element::precision: \
return std::make_shared<TensorMemoryBlob<T>>(tensor);
switch (tensor->get_element_type()) {
CASE(f32, float);
CASE(f64, double);
CASE(i4, int8_t);
CASE(i8, int8_t);
CASE(i16, int16_t);
CASE(i32, int32_t);
CASE(i64, int64_t);
CASE(u4, uint8_t);
CASE(u8, uint8_t);
CASE(u16, uint16_t);
CASE(u32, uint32_t);
CASE(u64, uint64_t);
CASE(u1, int8_t);
CASE(boolean, bool);
case element::f16:
return std::make_shared<TensorMemoryBlob<int16_t>>(tensor);
case element::bf16:
return std::make_shared<TensorMemoryBlob<int16_t>>(tensor);
default:
OPENVINO_THROW("Unsupported element type");
}
#undef CASE
}
OPENVINO_THROW("Cannot convert tensor to blob!");
}
} // namespace ov

View File

@ -7,7 +7,6 @@
#include <unordered_map> #include <unordered_map>
#include "cpp_interfaces/plugin_itt.hpp" #include "cpp_interfaces/plugin_itt.hpp"
#include "ie_blob.h"
#include "openvino/core/except.hpp" #include "openvino/core/except.hpp"
#include "openvino/core/layout.hpp" #include "openvino/core/layout.hpp"
#include "openvino/core/parallel.hpp" #include "openvino/core/parallel.hpp"
@ -248,16 +247,11 @@ void ov::ISyncInferRequest::check_tensor(const ov::Output<const ov::Node>& port,
" tensor size is not equal to the model ", " tensor size is not equal to the model ",
tensor_type, tensor_type,
" type: got ", " type: got ",
tensor.get_size(), tensor.get_shape(),
" expecting ", " expecting ",
port.get_shape(), port.get_shape(),
"."); ".");
OPENVINO_ASSERT(tensor.data() != nullptr, "Tensor data equal nullptr!"); OPENVINO_ASSERT(tensor.data() != nullptr, "Tensor data equal nullptr!");
// FIXME: SyncInferRequest is a friend only to check that blob is correct
OPENVINO_ASSERT(ov::shape_size(tensor._impl->getTensorDesc().getDims()) ==
ov::shape_size(tensor._impl->getTensorDesc().getBlockingDesc().getBlockDims()),
"Tensor is corrupted!");
} }
void ov::ISyncInferRequest::allocate_tensor(const ov::Output<const ov::Node>& port, void ov::ISyncInferRequest::allocate_tensor(const ov::Output<const ov::Node>& port,

View File

@ -0,0 +1,52 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "ie_blob.h"
#include "openvino/runtime/itensor.hpp"
namespace ov {
/**
* @brief Constructs Tensor using element type and shape. Allocate internal host storage using default allocator
* @param type Tensor element type
* @param shape Tensor shape
* @param allocator allocates memory for internal tensor storage
*/
std::shared_ptr<ITensor> make_tensor(const element::Type type, const Shape& shape, const Allocator& allocator = {});
/**
* @brief Constructs Tensor using element type and shape. Wraps allocated host memory.
* @note Does not perform memory allocation internally
* @param type Tensor element type
* @param shape Tensor shape
* @param host_ptr Pointer to pre-allocated host memory
* @param strides Optional strides parameters in bytes. Strides are supposed to be computed automatically based
* on shape and element size
*/
std::shared_ptr<ITensor> make_tensor(const element::Type type,
const Shape& shape,
void* host_ptr,
const Strides& strides = {});
/**
* @brief Constructs region of interest (ROI) tensor form another tensor.
* @note Does not perform memory allocation internally
* @param other original tensor
* @param begin start coordinate of ROI object inside of the original object.
* @param end end coordinate of ROI object inside of the original object.
* @note A Number of dimensions in `begin` and `end` must match number of dimensions in `other.get_shape()`
*/
std::shared_ptr<ITensor> make_tensor(const std::shared_ptr<ITensor>& other,
const Coordinate& begin,
const Coordinate& end);
/** @cond INTERNAL */
std::shared_ptr<ITensor> make_tensor(const std::shared_ptr<InferenceEngine::Blob>& tensor);
std::shared_ptr<InferenceEngine::Blob> tensor_to_blob(const std::shared_ptr<ITensor>& tensor);
/** @endcond */
} // namespace ov

View File

@ -4,22 +4,26 @@
#include "openvino/runtime/remote_tensor.hpp" #include "openvino/runtime/remote_tensor.hpp"
#include "any_copy.hpp" #include <memory>
#include "ie_ngraph_utils.hpp"
#include "ie_remote_blob.hpp" #include "openvino/runtime/iremote_tensor.hpp"
#include "openvino/runtime/itensor.hpp"
#include "openvino/runtime/properties.hpp"
namespace ov { namespace ov {
void RemoteTensor::type_check(const Tensor& tensor, const std::map<std::string, std::vector<std::string>>& type_info) { void RemoteTensor::type_check(const Tensor& tensor, const std::map<std::string, std::vector<std::string>>& type_info) {
OPENVINO_ASSERT(tensor, "Could not check empty tensor type"); OPENVINO_ASSERT(tensor, "Could not check empty tensor type");
auto remote_tensor = static_cast<const RemoteTensor*>(&tensor); auto remote_tensor = std::dynamic_pointer_cast<ov::IRemoteTensor>(tensor._impl);
auto remote_impl = dynamic_cast<ie::RemoteBlob*>(remote_tensor->_impl.get()); OPENVINO_ASSERT(remote_tensor, "Tensor is not remote.");
OPENVINO_ASSERT(remote_impl != nullptr, "Tensor was not initialized using remote implementation");
if (!type_info.empty()) { if (!type_info.empty()) {
auto params = remote_impl->getParams(); auto remote_properties = remote_tensor->get_properties();
for (auto&& type_info_value : type_info) { for (auto&& type_info_value : type_info) {
auto it_param = params.find(type_info_value.first); auto it_param = remote_properties.find(type_info_value.first);
OPENVINO_ASSERT(it_param != params.end(), "Parameter with key ", type_info_value.first, " not found"); OPENVINO_ASSERT(it_param != remote_properties.end(),
"Parameter with key ",
type_info_value.first,
" not found");
if (!type_info_value.second.empty()) { if (!type_info_value.second.empty()) {
auto param_value = it_param->second.as<std::string>(); auto param_value = it_param->second.as<std::string>();
auto param_found = std::any_of(type_info_value.second.begin(), auto param_found = std::any_of(type_info_value.second.begin(),
@ -34,12 +38,12 @@ void RemoteTensor::type_check(const Tensor& tensor, const std::map<std::string,
} }
AnyMap RemoteTensor::get_params() const { AnyMap RemoteTensor::get_params() const {
OPENVINO_ASSERT(_impl != nullptr, "Remote tensor was not initialized."); OPENVINO_ASSERT(_impl != nullptr, "Tensor was not initialized.");
type_check(*this); type_check(*this);
auto remote_impl = static_cast<ie::RemoteBlob*>(_impl.get()); auto remote_tensor = std::dynamic_pointer_cast<ov::IRemoteTensor>(_impl);
try { try {
AnyMap paramMap; AnyMap paramMap;
for (auto&& param : remote_impl->getParams()) { for (auto&& param : remote_tensor->get_properties()) {
paramMap.emplace(param.first, Any{param.second, _so}); paramMap.emplace(param.first, Any{param.second, _so});
} }
return paramMap; return paramMap;
@ -51,11 +55,12 @@ AnyMap RemoteTensor::get_params() const {
} }
std::string RemoteTensor::get_device_name() const { std::string RemoteTensor::get_device_name() const {
OPENVINO_ASSERT(_impl != nullptr, "Remote tensor was not initialized."); OPENVINO_ASSERT(_impl != nullptr, "Tensor was not initialized.");
auto remote_impl = static_cast<ie::RemoteBlob*>(_impl.get()); auto remote_tensor = std::dynamic_pointer_cast<ov::IRemoteTensor>(_impl);
OPENVINO_ASSERT(remote_tensor, "Tensor is not remote.");
type_check(*this); type_check(*this);
try { try {
return remote_impl->getDeviceName(); return remote_tensor->get_device_name();
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
OPENVINO_THROW(ex.what()); OPENVINO_THROW(ex.what());
} catch (...) { } catch (...) {

View File

@ -126,6 +126,13 @@ std::vector<std::string> disabledTestPatterns() {
// New plugin API doesn't support changes of pre-processing // New plugin API doesn't support changes of pre-processing
R"(.*InferRequestPreprocessTest.*SetPreProcessToInputInfo.*)", R"(.*InferRequestPreprocessTest.*SetPreProcessToInputInfo.*)",
R"(.*InferRequestPreprocessTest.*SetPreProcessToInferRequest.*)", R"(.*InferRequestPreprocessTest.*SetPreProcessToInferRequest.*)",
// New plugin work with tensors, so it means that blob in old API can have different pointers
R"(.*InferRequestIOBBlobTest.*secondCallGetInputDoNotReAllocateData.*)",
R"(.*InferRequestIOBBlobTest.*secondCallGetOutputDoNotReAllocateData.*)",
R"(.*InferRequestIOBBlobTest.*secondCallGetInputAfterInferSync.*)",
R"(.*InferRequestIOBBlobTest.*secondCallGetOutputAfterInferSync.*)",
// Old API cannot deallocate tensor
R"(.*InferRequestIOBBlobTest.*canProcessDeallocatedOutputBlobAfterGetAndSetBlob.*)",
}; };
#ifdef _WIN32 #ifdef _WIN32

View File

@ -122,10 +122,14 @@ TEST_P(InferRequestIOBBlobTest, failToSetInputWithIncorrectSizes) {
// Create InferRequest // Create InferRequest
InferenceEngine::InferRequest req; InferenceEngine::InferRequest req;
ASSERT_NO_THROW(req = execNet.CreateInferRequest()); ASSERT_NO_THROW(req = execNet.CreateInferRequest());
auto td = cnnNet.getInputsInfo().begin()->second->getTensorDesc();
auto dims = td.getDims();
dims[0] *= 2;
td.reshape(dims);
InferenceEngine::Blob::Ptr blob = InferenceEngine::Blob::Ptr blob =
FuncTestUtils::createAndFillBlob(cnnNet.getInputsInfo().begin()->second->getTensorDesc()); FuncTestUtils::createAndFillBlob(td);
blob->allocate(); blob->allocate();
blob->getTensorDesc().getDims()[0] *= 2;
ASSERT_THROW(req.SetBlob(cnnNet.getInputsInfo().begin()->first, blob), InferenceEngine::Exception); ASSERT_THROW(req.SetBlob(cnnNet.getInputsInfo().begin()->first, blob), InferenceEngine::Exception);
} }
@ -133,10 +137,14 @@ TEST_P(InferRequestIOBBlobTest, failToSetOutputWithIncorrectSizes) {
// Create InferRequest // Create InferRequest
InferenceEngine::InferRequest req; InferenceEngine::InferRequest req;
ASSERT_NO_THROW(req = execNet.CreateInferRequest()); ASSERT_NO_THROW(req = execNet.CreateInferRequest());
auto td = cnnNet.getOutputsInfo().begin()->second->getTensorDesc();
auto dims = td.getDims();
dims[0] *= 2;
td.reshape(dims);
InferenceEngine::Blob::Ptr blob = InferenceEngine::Blob::Ptr blob =
FuncTestUtils::createAndFillBlob(cnnNet.getOutputsInfo().begin()->second->getTensorDesc()); FuncTestUtils::createAndFillBlob(td);
blob->allocate(); blob->allocate();
blob->getTensorDesc().getDims()[0] *= 2;
ASSERT_THROW(req.SetBlob(cnnNet.getOutputsInfo().begin()->first, blob), InferenceEngine::Exception); ASSERT_THROW(req.SetBlob(cnnNet.getOutputsInfo().begin()->first, blob), InferenceEngine::Exception);
} }