Skip to content
Open
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
9 changes: 9 additions & 0 deletions cmake/onnxruntime_unittests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,15 @@ endif()

partition_provider_test_srcs(all_tests onnxruntime_provider_test_srcs onnxruntime_test_all_srcs)

if (onnxruntime_USE_OPENVINO)
# ov_protobuf_utils.cpp lives under core/providers (not test/), so partition_provider_test_srcs
# would route it to onnxruntime_test_all. Append it here after the partition so it is compiled into
# onnxruntime_provider_test alongside openvino_ov_protobuf_utils_test.cc, because the OpenVINO EP
# is a dynamically-loaded module and is not statically linked into the test binary.
list(APPEND onnxruntime_provider_test_srcs
${ONNXRUNTIME_ROOT}/core/providers/openvino/ov_protobuf_utils.cpp)
Comment thread
fdwr marked this conversation as resolved.
endif()

# Workarounds for onnxruntime test targets.
function(onnxruntime_apply_test_target_workarounds target)
if (MSVC)
Expand Down
31 changes: 27 additions & 4 deletions onnxruntime/core/providers/openvino/ov_protobuf_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include "ov_protobuf_utils.h"

#include <cstring>

#include "core/graph/onnx_protobuf.h"
#include "core/common/common.h"

Expand All @@ -11,14 +13,35 @@ namespace openvino_ep {
float get_float_initializer_data(const void* initializer) {
const auto* tp = reinterpret_cast<const ONNX_NAMESPACE::TensorProto*>(initializer);
ORT_ENFORCE((tp->has_data_type() && (tp->data_type() == ONNX_NAMESPACE::TensorProto_DataType_FLOAT)));
// ORT_ENFORCE(initializer.dims_size() == 1);
return tp->float_data(0);

// A FLOAT scalar/tensor may store its value either in the typed float_data
// field or in raw_data. Indexing float_data(0) when it is empty is undefined
// behavior, so pick the field that actually holds the data.
if (tp->float_data_size() > 0) {
return tp->float_data(0);
}

ORT_ENFORCE(tp->has_raw_data() && tp->raw_data().size() >= sizeof(float),
"FLOAT initializer has neither float_data nor sufficient raw_data to read a value");
float value;
std::memcpy(&value, tp->raw_data().data(), sizeof(float));
return value;
}
void set_float_initializer_data(const void* initializer, float data) {
auto* tp = (ONNX_NAMESPACE::TensorProto*)(initializer);
ORT_ENFORCE((tp->has_data_type() && (tp->data_type() == ONNX_NAMESPACE::TensorProto_DataType_FLOAT)));
// ORT_ENFORCE(initializer.dims_size() == 1);
tp->set_float_data(0, data);

// Mirror get_float_initializer_data: write back into whichever storage the
// initializer actually uses. set_float_data(0, data) on an empty float_data
// field is an out-of-bounds write.
if (tp->float_data_size() > 0) {
Comment thread
fdwr marked this conversation as resolved.
tp->set_float_data(0, data);
return;
}

ORT_ENFORCE(tp->has_raw_data() && tp->raw_data().size() >= sizeof(float),
"FLOAT initializer has neither float_data nor sufficient raw_data to write a value");
tp->set_raw_data(&data, sizeof(float));
}
} // namespace openvino_ep
} // namespace onnxruntime
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include <cstring>

#include "core/graph/onnx_protobuf.h"
#include "core/providers/openvino/ov_protobuf_utils.h"

#include "gtest/gtest.h"

using namespace ONNX_NAMESPACE;

namespace onnxruntime {
namespace test {

// Builds a FLOAT scalar whose value lives in raw_data, with an empty float_data
// field.
static TensorProto MakeRawDataFloatScalar(float value) {
TensorProto tp;
tp.set_data_type(TensorProto_DataType_FLOAT);
tp.set_raw_data(&value, sizeof(float));
return tp;
}

// Builds a FLOAT scalar whose value lives in the typed float_data field.
static TensorProto MakeFloatDataScalar(float value) {
TensorProto tp;
tp.set_data_type(TensorProto_DataType_FLOAT);
tp.add_float_data(value);
return tp;
}

TEST(OpenVINO_OvProtobufUtils, GetFromRawData) {
TensorProto tp = MakeRawDataFloatScalar(4.0f);
ASSERT_EQ(tp.float_data_size(), 0); // value is only in raw_data

EXPECT_FLOAT_EQ(openvino_ep::get_float_initializer_data(&tp), 4.0f);
}

TEST(OpenVINO_OvProtobufUtils, SetIntoRawData) {
TensorProto tp = MakeRawDataFloatScalar(4.0f);
ASSERT_EQ(tp.float_data_size(), 0);

openvino_ep::set_float_initializer_data(&tp, 0.5f);

// The write must land in raw_data (the field that actually holds the value),
// and must be readable back through the getter.
ASSERT_GE(tp.raw_data().size(), sizeof(float));
float stored;
std::memcpy(&stored, tp.raw_data().data(), sizeof(float));
EXPECT_FLOAT_EQ(stored, 0.5f);
EXPECT_FLOAT_EQ(openvino_ep::get_float_initializer_data(&tp), 0.5f);
}

TEST(OpenVINO_OvProtobufUtils, GetFromFloatData) {
TensorProto tp = MakeFloatDataScalar(3.0f);
EXPECT_FLOAT_EQ(openvino_ep::get_float_initializer_data(&tp), 3.0f);
}

TEST(OpenVINO_OvProtobufUtils, SetIntoFloatData) {
TensorProto tp = MakeFloatDataScalar(3.0f);
openvino_ep::set_float_initializer_data(&tp, 7.0f);
EXPECT_FLOAT_EQ(tp.float_data(0), 7.0f);
EXPECT_FLOAT_EQ(openvino_ep::get_float_initializer_data(&tp), 7.0f);
}

} // namespace test
} // namespace onnxruntime
Loading