Skip to content

[core] Fix ov::Tensor::data access perfomance #30673

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/core/dev_api/openvino/core/type/element_type_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (C) 2018-2025 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include <cstdint>
#include <string>

#include "openvino/core/type/element_type.hpp"

namespace ov::element {

struct TypeInfo {
size_t m_bitwidth;
bool m_is_real;
bool m_is_signed;
bool m_is_quantized;
const char* m_cname;
const char* m_type_name;
const char* const* m_aliases;
size_t m_alias_count;

bool has_name(const std::string& type) const {
if (type == m_type_name) {
return true;
} else {
const auto last = m_aliases + m_alias_count;
return std::find(m_aliases, last, type) != last;
}
}

constexpr bool is_valid() const {
return m_cname != nullptr && m_type_name != nullptr;
}
};

/**
* @brief Get TypeInfo of given element type.
*
* @param type Openvino element type to get its description.
* @return Reference to TypeInfo.
*/
OPENVINO_API const TypeInfo& get_type_info(Type_t type);

} // namespace ov::element
15 changes: 12 additions & 3 deletions src/core/dev_api/openvino/runtime/itensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,25 @@ class OPENVINO_API ITensor : public std::enable_shared_from_this<ITensor> {
*/
virtual const ov::Strides& get_strides() const = 0;

/**
* @brief Provides an access to the underlying host memory
* @return A host pointer to tensor memory
* @{
*/
virtual void* data() = 0;
virtual const void* data() const = 0;
/// @}

/**
* @brief Provides an access to the underlying host memory
* @param type Optional type parameter.
* @note If type parameter is specified, the method throws an exception
* @note 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 = {});
virtual const void* data(const element::Type& type = {}) const = 0;
virtual void* data(const element::Type& type) = 0;
virtual const void* data(const element::Type& type) const = 0;
/// @}

/**
Expand Down
23 changes: 18 additions & 5 deletions src/core/include/openvino/runtime/tensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,17 +219,30 @@ class OPENVINO_API Tensor {

/**
* @brief Provides an access to the underlying 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
* @{
*/

#ifndef IN_OV_COMPONENT
OPENVINO_DEPRECATED("This function will return const void* in 2026.0. Check if used correctly")
#endif
void* data() const;
void* data();
/// @}

/**
* @brief Provides an access to the underlying host memory
* @param type Optional type parameter.
* @note 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
* @{
*/
#ifndef IN_OV_COMPONENT
OPENVINO_DEPRECATED("This function will return const void* in 2026.0. Check if used correctly")
#endif
void* data(const element::Type& type = {}) const;
void* data(const element::Type& type = {});
void* data(const element::Type& type) const;
void* data(const element::Type& type);
/// @}

/**
Expand Down
5 changes: 0 additions & 5 deletions src/core/src/runtime/itensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,4 @@ void ITensor::copy_to(const std::shared_ptr<ov::ITensor>& dst) const {
dst_idx = update_index(cur_pos, dst_strides);
}
}

void* ITensor::data(const element::Type& type) {
return const_cast<void*>(static_cast<const ITensor*>(this)->data(type));
}

} // namespace ov
8 changes: 8 additions & 0 deletions src/core/src/runtime/tensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ size_t Tensor::get_byte_size() const {
OV_TENSOR_STATEMENT(return _impl->get_byte_size(););
}

void* Tensor::data() {
OV_TENSOR_STATEMENT(return _impl->data());
}

void* Tensor::data() const {
OV_TENSOR_STATEMENT(return const_cast<void*>(std::as_const(*_impl).data()););
}

void* Tensor::data(const element::Type& element_type) {
OV_TENSOR_STATEMENT(return _impl->data(element_type));
}
Expand Down
39 changes: 8 additions & 31 deletions src/core/src/type/element_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <string_view>
#include <unordered_map>

#include "openvino/core/type/element_type_info.hpp"
#include "openvino/core/type/element_type_traits.hpp"
#include "openvino/util/common_util.hpp"

Expand All @@ -22,30 +23,6 @@ constexpr size_t idx(Type_t e) noexcept {
// Update it when new type is added
constexpr size_t enum_types_size = idx(f8e8m0) + 1;

struct TypeInfo {
size_t m_bitwidth;
bool m_is_real;
bool m_is_signed;
bool m_is_quantized;
const char* m_cname;
const char* m_type_name;
const char* const* aliases;
size_t alias_count;

bool has_name(const std::string& type) const {
if (type == m_type_name) {
return true;
} else {
const auto last = aliases + alias_count;
return std::find(aliases, last, type) != last;
}
}

constexpr bool is_valid() const {
return m_cname != nullptr && m_type_name != nullptr;
}
};

template <class Array>
constexpr TypeInfo type_info(size_t bitwidth,
bool is_real,
Expand Down Expand Up @@ -133,12 +110,6 @@ size_t type_idx_for(const std::string& type_name) {
return type_idx;
}

const TypeInfo& get_type_info(Type_t type) {
const auto type_idx = idx(type);
OPENVINO_ASSERT(is_valid_type_idx(type_idx), "Type_t not supported: ", type_idx);
return types_info[type_idx];
}

Type type_from_string(const std::string& type) {
const auto type_idx = type_idx_for(type);
OPENVINO_ASSERT(is_valid_type_idx(type_idx), "Unsupported element type: ", type);
Expand All @@ -155,6 +126,12 @@ static constexpr auto known_types = [] {
}();
} // namespace

const TypeInfo& get_type_info(Type_t type) {
const auto type_idx = idx(type);
OPENVINO_ASSERT(is_valid_type_idx(type_idx), "Type_t not supported: ", type_idx);
return types_info[type_idx];
}

std::vector<const Type*> Type::get_known_types() {
std::vector<const Type*> result(known_types.size());
for (size_t i = 0; i < known_types.size(); ++i) {
Expand Down Expand Up @@ -275,7 +252,7 @@ bool Type::merge(Type& dst, const Type& t1, const Type& t2) {
}

bool Type::is_static() const {
return get_type_info(m_type).m_bitwidth != 0;
return m_type != Type_t::dynamic;
}

bool Type::is_real() const {
Expand Down
13 changes: 12 additions & 1 deletion src/inference/dev_api/openvino/runtime/iremote_tensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,18 @@ namespace ov {

class OPENVINO_RUNTIME_API IRemoteTensor : public ITensor {
public:
const void* data(const element::Type& type = {}) const override final {
void* data() override final {
OPENVINO_NOT_IMPLEMENTED;
}

void* data(const element::Type&) override final {
OPENVINO_NOT_IMPLEMENTED;
}
const void* data() const override final {
OPENVINO_NOT_IMPLEMENTED;
}

const void* data(const element::Type&) const override final {
OPENVINO_NOT_IMPLEMENTED;
}

Expand Down
66 changes: 52 additions & 14 deletions src/inference/src/dev/make_tensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <mutex>

#include "openvino/core/type/element_iterator.hpp"
#include "openvino/core/type/element_type_info.hpp"
#include "openvino/runtime/iremote_tensor.hpp"
#include "openvino/runtime/properties.hpp"
#include "openvino/runtime/tensor.hpp"
Expand Down Expand Up @@ -57,13 +58,29 @@ class ViewTensor : public ITensor {
OPENVINO_ASSERT(m_element_type.is_static());
}

void* data() override {
return m_ptr;
}

void* data(const element::Type& element_type) override {
OPENVINO_ASSERT(is_pointer_representable(element_type),
"Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
return m_ptr;
}

const void* data() const override {
return m_ptr;
}

const void* data(const element::Type& element_type) const override {
if (!is_pointer_representable(element_type)) {
OPENVINO_THROW("Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
}
OPENVINO_ASSERT(is_pointer_representable(element_type),
"Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
return m_ptr;
}

Expand Down Expand Up @@ -92,11 +109,17 @@ class ViewTensor : public ITensor {

protected:
bool is_pointer_representable(const element::Type& element_type) const {
return element_type.is_dynamic() ||
((get_element_type() != element::string && element_type != element::string &&
element_type.bitwidth() == get_element_type().bitwidth() &&
element_type.is_real() == get_element_type().is_real()) ||
(element_type == element::string && element::string == get_element_type()));
if (element_type.is_dynamic()) {
return true;
} else {
// gets type info to reduce validation to access speed, due to performance issues
const auto& other_type_info = element::get_type_info(element_type);
const auto& this_type_info = element::get_type_info(get_element_type());
return (get_element_type() != element::string && element_type != element::string &&
other_type_info.m_bitwidth == this_type_info.m_bitwidth &&
other_type_info.m_is_real == this_type_info.m_is_real) ||
(element_type == element::string && element::string == get_element_type());
}
}

void update_strides() const {
Expand Down Expand Up @@ -134,9 +157,13 @@ class ReadOnlyViewTensor : public ViewTensor {

using ViewTensor::data;

[[noreturn]] void* data(const element::Type& element_type) override {
[[noreturn]] void* data() override {
OPENVINO_THROW("Can not access non-const pointer use e.g. 'static_cast<const ov::Tensor&>.data()'");
}

[[noreturn]] void* data(const element::Type& element_type) override {
OPENVINO_THROW("Can not access non-const pointer use e.g. 'static_cast<const ov::Tensor&>.data(element_type)'");
}
};

/**
Expand Down Expand Up @@ -416,9 +443,20 @@ class RoiTensor : public BaseRoiTensor, public ITensor {
BaseRoiTensor::set_shape(new_shape);
}

void* data() override {
return static_cast<uint8_t*>(m_owner->data()) + m_offset;
}

void* data(const element::Type& element_type) override {
return static_cast<uint8_t*>(m_owner->data()) + m_offset;
}

const void* data() const override {
return static_cast<uint8_t*>(m_owner->data()) + m_offset;
}

const void* data(const element::Type& element_type) const override {
auto owner_data = m_owner->data(element_type);
return static_cast<uint8_t*>(owner_data) + m_offset;
return static_cast<uint8_t*>(m_owner->data()) + m_offset;
}
};

Expand Down
35 changes: 28 additions & 7 deletions src/plugins/intel_cpu/src/cpu_tensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@
#include "openvino/core/except.hpp"
#include "openvino/core/shape.hpp"
#include "openvino/core/strides.hpp"
#include "openvino/core/type/element_type.hpp"
#include "openvino/runtime/itensor.hpp"
#include "utils/debug_capabilities.h"
#include "utils/general_utils.h"

namespace ov::intel_cpu {
namespace {
constexpr bool is_pointer_representable(const ov::element::Type& tensor_type, const ov::element::Type& type) {
return type == ov::element::dynamic || tensor_type == type;
}
} // namespace

Tensor::Tensor(MemoryPtr memptr) : m_memptr{std::move(memptr)} {
OPENVINO_ASSERT(m_memptr != nullptr);
Expand Down Expand Up @@ -93,14 +99,29 @@ void Tensor::update_strides() const {
});
}

void* Tensor::data() {
return m_memptr->getData();
}

void* Tensor::data(const element::Type& element_type) {
OPENVINO_ASSERT(is_pointer_representable(get_element_type(), element_type),
"Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
return m_memptr->getData();
}

const void* Tensor::data() const {
return m_memptr->getData();
}

const void* Tensor::data(const element::Type& element_type) const {
if (element_type.is_static()) {
OPENVINO_ASSERT(element_type == get_element_type(),
"Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
}
OPENVINO_ASSERT(is_pointer_representable(get_element_type(), element_type),
"Tensor data with element type ",
get_element_type(),
", is not representable as pointer to ",
element_type);
return m_memptr->getData();
}

Expand Down
Loading
Loading