1 // Copyright (C) 2018-2020 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
6 * @brief A header file for Blob and generic TBlob<>
18 #include <type_traits>
22 #include "details/ie_blob_iterator.hpp"
23 #include "details/ie_exception.hpp"
24 #include "details/ie_pre_allocator.hpp"
25 #include "ie_allocator.hpp"
26 #include "ie_common.h"
27 #include "ie_layouts.h"
28 #include "ie_locked_memory.hpp"
29 #include "ie_precision.hpp"
31 namespace InferenceEngine {
33 * @brief This class represents a universal container in the Inference Engine
35 * @note Each Blob implementation must be derived from this Blob class directly or indirectly
37 class INFERENCE_ENGINE_API_CLASS(Blob) {
40 * @brief A smart pointer containing Blob object
42 using Ptr = std::shared_ptr<Blob>;
45 * @brief A smart pointer to the const Blob object
47 using CPtr = std::shared_ptr<const Blob>;
50 * @brief Creates a TBlob<> object from a Data node
52 * @param Data reference to a smart pointer of the Data node
53 * @return Smart pointer to TBlob<> with the relevant C type to the precision of the data node
55 static Ptr CreateFromData(const DataPtr& data);
58 * @brief Blob virtual destructor
63 * @brief Checks if the Blob object can be cast to the type T*
65 * @tparam T Type to be checked. Must represent a class derived from the Blob
66 * @return true if this object can be dynamically cast to the type T*. Otherwise, false
69 typename std::enable_if<!std::is_pointer<T>::value && !std::is_reference<T>::value, int>::type = 0,
70 typename std::enable_if<std::is_base_of<Blob, T>::value, int>::type = 0>
72 return dynamic_cast<T*>(this) != nullptr;
76 * @brief Checks if the Blob object can be cast to the type const T*
78 * @tparam T Type to be checked. Must represent a class derived from the Blob
79 * @return true if this object can be dynamically cast to the type const T*. Otherwise, false
82 typename std::enable_if<!std::is_pointer<T>::value && !std::is_reference<T>::value, int>::type = 0,
83 typename std::enable_if<std::is_base_of<Blob, T>::value, int>::type = 0>
84 bool is() const noexcept {
85 return dynamic_cast<const T*>(this) != nullptr;
89 * @brief Casts this Blob object to the type T*.
91 * Use InferenceEngine::as() to operate with shared Blob objects instead of raw pointers
93 * @tparam T Type to cast to. Must represent a class derived from the Blob
94 * @return Raw pointer to the object of the type T or nullptr on error
97 typename std::enable_if<!std::is_pointer<T>::value && !std::is_reference<T>::value, int>::type = 0,
98 typename std::enable_if<std::is_base_of<Blob, T>::value, int>::type = 0>
100 return dynamic_cast<T*>(this);
104 * @brief Casts this Blob object to the type const T*.
106 * Use InferenceEngine::as() to operate with shared Blob objects instead of raw pointers
108 * @tparam T Type to cast to. Must represent a class derived from the Blob
109 * @return Raw pointer to the object of the type const T or nullptr on error
111 template <typename T,
112 typename std::enable_if<!std::is_pointer<T>::value && !std::is_reference<T>::value, int>::type = 0,
113 typename std::enable_if<std::is_base_of<Blob, T>::value, int>::type = 0>
114 const T* as() const noexcept {
115 return dynamic_cast<const T*>(this);
119 * @brief Constructor. Creates an empty Blob object with the specified precision.
121 * @param tensorDesc Defines the layout and dims of the blob
123 explicit Blob(const TensorDesc& tensorDesc): tensorDesc(tensorDesc) {}
126 * @brief Returns the tensor description
128 virtual const TensorDesc& getTensorDesc() const noexcept {
133 * @brief Returns the tensor description
135 virtual TensorDesc& getTensorDesc() noexcept {
140 * @brief By default, returns the total number of elements (a product of all the dims or 1 for scalar)
142 * Return value and its interpretation heavily depend on the blob type
144 virtual size_t size() const noexcept {
145 if (tensorDesc.getLayout() == Layout::SCALAR) return 1;
146 return product(tensorDesc.getDims());
150 * @brief Returns the size of the current Blob in bytes.
152 virtual size_t byteSize() const noexcept {
153 return size() * element_size();
157 * @deprecated Cast to MemoryBlob and use its API instead.
158 * Blob class can represent compound blob, which do not refer to the only solid memory.
160 * @brief Returns the number of bytes per element.
162 * The overall Blob capacity is size() * element_size(). Abstract method.
164 virtual size_t element_size() const noexcept = 0;
167 * @brief Allocates memory to store the data.
171 virtual void allocate() noexcept = 0;
174 * @brief Releases previously allocated data.
178 virtual bool deallocate() noexcept = 0;
181 * @deprecated Cast to MemoryBlob and use new wlock/rwlock API instead.
182 * Blob class can represent compound blob, which do not refer to the only solid memory.
183 * @brief Gets access to the allocated memory.
187 * @return A LockedMemory object
189 virtual LockedMemory<void> buffer() noexcept = 0;
192 * @deprecated Cast to MemoryBlob and use new MemoryBlob::rmap() function instead.
193 * Blob class can represent compound blob, which do not refer to the only solid memory.
194 * @brief Gets read-only access to the allocated memory.
198 * @return A LockedMemory object
200 virtual LockedMemory<const void> cbuffer() const noexcept = 0;
204 * @brief The tensor descriptor of the given blob.
206 TensorDesc tensorDesc;
209 * @deprecated Cast to MemoryBlob and use its API instead.
210 * @brief Multiplies the dimension vector values.
212 * @param dims Reference to a vector with dimension values of type size_t
213 * @return Result of multiplication
215 static size_t product(const SizeVector& dims) noexcept {
216 if (dims.empty()) return 0;
217 return std::accumulate(std::begin(dims), std::end(dims), (size_t)1, std::multiplies<size_t>());
221 * @brief Gets an allocator for allocator-based blobs
223 * @return The allocator for allocator-based blobs or nullptr if there is none
225 virtual const std::shared_ptr<IAllocator>& getAllocator() const noexcept = 0;
228 * @brief Gets a handle to allocated memory
230 * @return The handle to allocated memory for allocator-based blobs or nullptr if there is none
232 virtual void* getHandle() const noexcept = 0;
235 friend class TBlobProxy;
239 * @brief Helper cast function to work with shared Blob objects
241 * @return shared_ptr to the type T. Returned shared_ptr shares ownership of the object with the
244 template <typename T,
245 typename std::enable_if<!std::is_pointer<T>::value && !std::is_reference<T>::value, int>::type = 0,
246 typename std::enable_if<std::is_base_of<Blob, T>::value, int>::type = 0>
247 std::shared_ptr<T> as(const Blob::Ptr& blob) noexcept {
248 return std::dynamic_pointer_cast<T>(blob);
252 * @brief Helper cast function to work with shared Blob objects
254 * @return shared_ptr to the type const T. Returned shared_ptr shares ownership of the object with
255 * the input Blob::Ptr
257 template <typename T,
258 typename std::enable_if<!std::is_pointer<T>::value && !std::is_reference<T>::value, int>::type = 0,
259 typename std::enable_if<std::is_base_of<Blob, T>::value, int>::type = 0>
260 std::shared_ptr<const T> as(const Blob::CPtr& blob) noexcept {
261 return std::dynamic_pointer_cast<const T>(blob);
265 * @brief This class implements a container object that represents a tensor in memory (host and
266 * remote/accelerated)
268 * @note Any Blob implementation that represents a concept of a tensor in memory (for example,
269 * TBlob) must be a subclass of MemoryBlob instead of Blob
271 class INFERENCE_ENGINE_API_CLASS(MemoryBlob): public Blob {
274 * @brief A smart pointer to the MemoryBlob object
276 using Ptr = std::shared_ptr<MemoryBlob>;
279 * @brief A smart pointer to the const MemoryBlob object
281 using CPtr = std::shared_ptr<const MemoryBlob>;
284 * @brief MemoryBlob virtual destructor
286 virtual ~MemoryBlob();
289 * @brief Constructor. Creates an empty MemoryBlob object with the specified precision.
291 * @param tensorDesc Defines the layout and dims of the blob
293 explicit MemoryBlob(const TensorDesc& tensorDesc): Blob(tensorDesc) {}
296 * @brief Returns the tensor description
298 const TensorDesc& getTensorDesc() const noexcept override {
303 * @brief Returns the tensor description
305 TensorDesc& getTensorDesc() noexcept override {
310 * @brief Returns the total number of elements, which is a product of all the dimensions
312 size_t size() const noexcept override {
313 if (tensorDesc.getLayout() == Layout::SCALAR) return 1;
314 return product(tensorDesc.getDims());
318 * @brief Returns the size of the current Blob in bytes
320 size_t byteSize() const noexcept override {
321 return size() * element_size();
325 * @brief Returns the number of bytes per element.
327 * The overall MemoryBlob capacity is size() * element_size().
330 size_t element_size() const noexcept override = 0;
333 * @brief Allocates memory to store the data.
337 void allocate() noexcept override = 0;
340 * @brief Releases previously allocated data.
344 bool deallocate() noexcept override = 0;
347 * @deprecated Use wmap() or rwmap() API instead.
348 * @brief Gets access to the allocated memory.
352 * @return A LockedMemory object
354 LockedMemory<void> buffer() noexcept override = 0;
357 * @deprecated Use rmap() function instead.
358 * @brief Gets read-only access to the allocated memory.
362 * @return A LockedMemory object
364 LockedMemory<const void> cbuffer() const noexcept override = 0;
367 * @brief Gets read/write access to the memory in virtual space of the process.
368 * The function returns object which retains mapped memory.
369 * The memory been addressed in the MemoryBlob in general case can be allocated on remote device.
370 * This function maps remote memory to the memory in the virtual process space and after destruction
371 * of the LockedMemory will upload changed content to the accelerator.
373 * To avoid extra copy of data, you can use rmap() and wmap() functions.
375 * In case of memory originally allocated on the host, this function returns LockedMemory which will
376 * transparently refer to original memory address. No extra copy will happen
378 * In general case, pointer received from that LockedMemory becomes invalid just after
379 * destruction of LockedMemory instance. Keep Locked memory alive while you need to address memory
380 * in the process on the host.
384 * @return A LockedMemory object
386 virtual LockedMemory<void> rwmap()noexcept = 0;
389 * @brief Gets read only access to the memory in virtual space of the process.
390 * The function returns object which retains mapped memory.
392 * The memory been addressed in the MemoryBlob in general case can be allocated on remote device.
393 * This function copies remote memory to the memory in the virtual process space and after
394 * destruction of the LockedMemory it will not upload host memory back, bacause it is expected that
395 * content is not changed.
397 * To have an ability change content, you can use rwmap() and wmap() functions.
399 * In case of memory originally allocated on the host, this function returns LockedMemory which will
400 * transparently refer to original memory address. No extra copy will happen
402 * In general case, pointer received from that LockedMemory becomes invalid just after destruction
403 * of LockedMemory instance. Keep Locked memory alive while you need to address memory in the
404 * process on the host.
408 * @return A LockedMemory object
410 virtual LockedMemory<const void> rmap()const noexcept = 0;
413 * @brief Gets "write only direction" access to the memory in virtual space of the process.
414 * The function returns object which retains memory to be uploaded on device.
416 * The memory been addressed in the MemoryBlob in general case can be allocated on remote device.
417 * This function does not copy of the content from the device to the memory in the virtual process
418 * space, the content of the memory just after calling of this functin is not specified. After
419 * destruction of the LockedMemory, content will be upload host memory.
420 * In the same time there is no abilities to restrict reading from the memory, you need to care of
421 * reading from memory got by wmap(), it might have sence in some cases like filling of content and
422 * before uploading to device
424 * To access data stored in the blob, you can use rwmap() and rmap() functions.
426 * In case of memory originally allocated on the host, this function returns LockedMemory which will
427 * transparently refer to original memory address. No extra copy will happen
429 * In general case, pointer received from that LockedMemory becomes invalid just after destruction
430 * of LockedMemory instance. Keep Locked memory alive while you need to address memory in the
431 * process on the host.
435 * @return A LockedMemory object
437 virtual LockedMemory<void> wmap()noexcept = 0;
443 * @brief Gets the allocator for allocator-based blobs.
445 * @return The allocator for allocator-based blobs or if there is none then a nullptr.
447 const std::shared_ptr<IAllocator>& getAllocator() const noexcept override = 0;
450 * @brief Gets the handle to allocated memory.
452 * @return The handle to allocated memory for allocator-based blobs or if there is none then a nullptr.
454 void* getHandle() const noexcept override = 0;
457 friend class TBlobProxy;
461 * @brief This is a convenient type for working with a map containing pairs(string, pointer to a Blob instance).
463 using BlobMap = std::map<std::string, Blob::Ptr>;
466 * @brief Represents real host memory allocated for a Tensor/Blob per C type.
468 template <typename T, typename = std::enable_if<std::is_pod<T>::value>>
469 class TBlob : public MemoryBlob {
470 template <typename, typename>
475 * @brief Smart Pointer to this TBlob object.
477 using Ptr = std::shared_ptr<TBlob<T>>;
480 * @brief Creates a TBlob object with the specified dimensions and layout but does not allocate the memory.
482 * Use the allocate() method to allocate memory.
484 * @param tensorDesc Tensor description
486 explicit TBlob(const TensorDesc& tensorDesc): MemoryBlob(tensorDesc) {}
489 * @brief The constructor creates a TBlob object with the specified dimensions and layout
490 * on the pre-allocated memory.
492 * The allocate() call is not required.
494 * @param tensorDesc Tensor description
495 * @param ptr Pointer to the pre-allocated memory
496 * @param data_size Length of the pre-allocated array. If not set, size is assumed equal
497 * to the dot product of dims.
499 TBlob(const TensorDesc& tensorDesc, T* ptr, size_t data_size = 0): MemoryBlob(tensorDesc) {
500 if (data_size == 0) {
504 if (data_size != 0 && ptr == nullptr) {
505 THROW_IE_EXCEPTION << "Using Blob on external nullptr memory";
508 _allocator = details::make_pre_allocator(ptr, data_size);
509 // blob on attached memory is always allocated, so we are not forcing the user to call allocate()
514 * @brief Creates a TBlob object with the specified dimensions, layout and custom memory allocator but does not
515 * allocate the memory.
519 * @param dims Tensor dimensions
520 * @param alloc Allocator to be used
522 TBlob(const TensorDesc& tensorDesc, const std::shared_ptr<IAllocator>& alloc)
523 : MemoryBlob(tensorDesc), _allocator(alloc) {}
526 * @brief The copy constructor data is reallocated and copied from the source to the target blob.
528 * @param blob Source blob
530 TBlob(const TBlob<T>& blob): MemoryBlob(blob.getTensorDesc()) {
535 * @brief A move constructor.
537 * @param blob rvalue to make a move from
539 TBlob(TBlob<T>&& blob): MemoryBlob(blob.getTensorDesc()) {
544 * @brief Copy operator for the TBlob object.
546 * @param blob object reference to copy from
547 * @return Newly copied object
549 TBlob& operator=(const TBlob& blob) {
555 *@brief Virtual destructor.
566 * @brief Gets the size of the given type.
568 * @return Size of the type
570 size_t element_size() const noexcept override {
575 * @brief Creates an new empty rvalue LockedMemory object.
577 * @return rvalue for the empty locked object of type T
579 virtual LockedMemory<T> data() noexcept {
580 return std::move(lockme<T>());
584 * @brief Creates a new empty rvalue read-only LockedMemory object.
586 * @return rvalue for the empty locked const object of type T.
588 virtual LockedMemory<const T> readOnly() const noexcept {
589 return std::move(lockme<const T>());
593 * @brief Allocates or reallocates memory
595 void allocate() noexcept override {
596 if (_handle != nullptr) {
597 getAllocator()->free(_handle);
599 _handle = getAllocator()->alloc(size() * sizeof(T));
603 * @brief Frees all allocated data
605 bool deallocate() noexcept override {
610 * @brief Creates a new LockedMemory instance holding void pointer.
612 * @return LockedMemory instance holding void pointer
614 LockedMemory<void> buffer() noexcept override {
615 return std::move(lockme<void>());
619 * @brief Creates a new LockedMemory instance holding constant void pointer.
621 * @return LockedMemory instance holding constant void pointer
623 LockedMemory<const void> cbuffer() const noexcept override {
624 return std::move(lockme<const void>());
627 LockedMemory<void> rwmap()noexcept override {
628 return std::move(lockme<void>());
631 LockedMemory<const void> rmap() const noexcept override {
632 return std::move(lockme<const void>());
634 LockedMemory<void> wmap()noexcept override {
635 return std::move(lockme<void>());
639 * @brief Gets BlobIterator for the data.
641 * Enables a ranged loop support for the TBlob object.
643 * @return BlobIterator object of type T
645 details::BlobIterator<T> begin() {
646 return details::BlobIterator<T>(data());
650 * @brief Gets BlobIterator for the end of data.
652 * Enables a ranged loop support for the TBlob object.
654 * @return BlobIterator object of type T representing end of the data
656 details::BlobIterator<T> end() {
657 return details::BlobIterator<T>(data(), size());
661 * @brief Gets a const BlobIterator for the read-only data.
663 * Enables a ranged loop support for the TBlob object.
665 * @return BlobIterator object of type const T
667 details::BlobIterator<const T> begin() const {
668 return details::BlobIterator<const T>(readOnly());
672 * @brief Gets a const BlobIterator for the end of read-only data.
674 * Enables a ranged loop support for the TBlob object.
676 * @return BlobIterator object of type const T representing end of data
678 details::BlobIterator<const T> end() const {
679 return details::BlobIterator<const T>(readOnly(), size());
684 * @brief Local instance of IAllocator to manipulate memory.
686 mutable std::shared_ptr<IAllocator> _allocator;
689 * @brief A handle for the stored memory returned from _allocator.alloc().
691 void* _handle = nullptr;
694 * @brief Copies dimensions and data from the TBlob object.
696 * @param blob object reference to copy from
698 void copyFrom(const TBlob<T>& blob) {
699 tensorDesc = blob.tensorDesc;
701 auto memptr = data();
702 memcpy(memptr, blob.readOnly(), byteSize());
706 * @brief Swaps memory handlers between the current blob and the given one.
708 * @tparam U Type of the blob to move from
709 * @param blob TBlob instance to move from
712 void moveFrom(TBlob<U>& blob) {
713 tensorDesc = blob.tensorDesc;
714 this->_allocator = std::move(blob._allocator);
715 std::swap(this->_handle, blob._handle);
719 * @brief Frees handler and cleans up the stored data.
721 virtual bool free() {
722 bool bCanRelease = getAllocator()->free(_handle);
728 * @brief Creates a LockedMemory instance.
730 * @tparam S Type of the LockedMemory to be created
731 * @return A created instance of LockedMemory
734 LockedMemory<S> lockme() const {
735 return LockedMemory<S>(_allocator.get(), _handle, 0);
739 * @brief Gets an allocator or creates a default one.
741 * @return IAllocator instance
743 const std::shared_ptr<IAllocator>& getAllocator() const noexcept override {
744 // in case when constructor without allocator was used
746 _allocator = shared_from_irelease(CreateDefaultAllocator());
753 * @brief Returns handle to the stored data.
755 void* getHandle() const noexcept override {
761 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<float>);
762 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<double>);
763 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<int16_t>);
764 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<uint16_t>);
765 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<int8_t>);
766 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<uint8_t>);
767 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<int>);
768 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<long>);
769 extern template class INFERENCE_ENGINE_API_CLASS(InferenceEngine::TBlob<long long>);
773 * @brief Creates a blob with the given tensor descriptor.
775 * @tparam Type Type of the shared pointer to be created
776 * @param tensorDesc Tensor descriptor for Blob creation
777 * @return A shared pointer to the newly created blob of the given type
779 template <typename Type>
780 inline typename InferenceEngine::TBlob<Type>::Ptr make_shared_blob(const TensorDesc& tensorDesc) {
781 if (!tensorDesc.getPrecision().hasStorageType<Type>())
782 THROW_IE_EXCEPTION << "Cannot make shared blob! "
783 << "The blob type cannot be used to store objects of current precision";
784 return std::make_shared<InferenceEngine::TBlob<Type>>(tensorDesc);
788 * @brief Creates a blob with the given tensor descriptor from the pointer to the pre-allocated memory.
790 * @tparam Type Type of the shared pointer to be created
791 * @param tensorDesc TensorDesc for Blob creation
792 * @param ptr Pointer to the pre-allocated memory
793 * @param size Length of the pre-allocated array
794 * @return A shared pointer to the newly created blob of the given type
796 template <typename Type>
797 inline typename InferenceEngine::TBlob<Type>::Ptr make_shared_blob(const TensorDesc& tensorDesc, Type* ptr,
799 if (!tensorDesc.getPrecision().hasStorageType<Type>())
800 THROW_IE_EXCEPTION << "Cannot make shared blob! "
801 << "The blob type cannot be used to store objects of current precision";
802 return std::make_shared<InferenceEngine::TBlob<Type>>(tensorDesc, ptr, size);
806 * @brief Creates a blob with the given tensor descriptor and allocator.
808 * @tparam Type Type of the shared pointer to be created
809 * @param tensorDesc Tensor descriptor for Blob creation
810 * @param alloc Shared pointer to IAllocator to use in the blob
811 * @return A shared pointer to the newly created blob of the given type
813 template <typename Type>
814 inline typename InferenceEngine::TBlob<Type>::Ptr make_shared_blob(
815 const TensorDesc& tensorDesc, const std::shared_ptr<InferenceEngine::IAllocator>& alloc) {
816 if (!tensorDesc.getPrecision().hasStorageType<Type>())
817 THROW_IE_EXCEPTION << "Cannot make shared blob! "
818 << "The blob type cannot be used to store objects of current precision";
819 return std::make_shared<InferenceEngine::TBlob<Type>>(tensorDesc, alloc);
823 * @brief Creates a copy of given TBlob instance.
825 * @tparam TypeTo Type of the shared pointer to be created
826 * @param arg given pointer to blob
827 * @return A shared pointer to the newly created blob of the given type
829 template <typename TypeTo>
830 inline typename InferenceEngine::TBlob<TypeTo>::Ptr make_shared_blob(const TBlob<TypeTo>& arg) {
831 return std::make_shared<InferenceEngine::TBlob<TypeTo>>(arg);
835 * @brief Creates a Blob object of the specified type
837 * @param args Constructor arguments for the Blob object
838 * @return A shared pointer to the newly created Blob object
840 template <typename T, typename... Args, typename std::enable_if<std::is_base_of<Blob, T>::value, int>::type = 0>
841 std::shared_ptr<T> make_shared_blob(Args&&... args) {
842 return std::make_shared<T>(std::forward<Args>(args)...);
846 * @brief This structure describes ROI data.
849 size_t id; // ID of a ROI
850 size_t posX; // W upper left coordinate of ROI
851 size_t posY; // H upper left coordinate of ROI
852 size_t sizeX; // W size of ROI
853 size_t sizeY; // H size of ROI
857 * @brief Creates a blob describing given ROI object based on the given blob with pre-allocated memory.
859 * @param inputBlob original blob with pre-allocated memory.
860 * @param roi A ROI object inside of the original blob.
861 * @return A shared pointer to the newly created blob.
863 INFERENCE_ENGINE_API_CPP(Blob::Ptr) make_shared_blob(const Blob::Ptr& inputBlob, const ROI& roi);
865 } // namespace InferenceEngine