[Time tests] Add API 2.0 support (#9878)

* add performance hint to time infer

* init commit - add api 2 support

* change imInfo filling

* change copyright dates

* check hw positions to default

* add debug info

* fix mistake

* add check layout funcs for api2 time infer

* reformat code (2 -> 4)

* upd with reshape api2

* upd with master

* --

* fix fillTensors - set as template

* fix common_utils.cpp after merge master
This commit is contained in:
Victor Kuznetsov authored and GitHub committed 2022-02-02 12:33:02 +03:00
1 parent 70f65bdb74
commit 0dd8d895a0
12 files changed
+532 -318

No files matched your search

+3 -32
View File
@@ -4,9 +4,6 @@
#include "common_utils.h"
#include <inference_engine.hpp>
#include <openvino/openvino.hpp>
/**
* @brief Fill InferRequest blobs with random values or image information
@@ -15,6 +12,7 @@ void fillBlobs(InferenceEngine::InferRequest inferRequest,
const InferenceEngine::ConstInputsDataMap &inputsInfo,
const size_t &batchSize) {
std::vector<std::pair<size_t, size_t>> input_image_sizes;
for (const InferenceEngine::ConstInputsDataMap::value_type &item: inputsInfo) {
if (isImage(item.second))
input_image_sizes.push_back(getTensorHeightWidth(item.second->getTensorDesc()));
@@ -22,6 +20,7 @@ void fillBlobs(InferenceEngine::InferRequest inferRequest,
for (const InferenceEngine::ConstInputsDataMap::value_type &item: inputsInfo) {
InferenceEngine::Blob::Ptr inputBlob = inferRequest.GetBlob(item.first);
if (isImageInfo(inputBlob) && (input_image_sizes.size() == 1)) {
// Fill image information
auto image_size = input_image_sizes.at(0);
@@ -57,32 +56,4 @@ void fillBlobs(InferenceEngine::InferRequest inferRequest,
throw std::logic_error("Input precision is not supported for " + item.first);
}
}
}
/**
* @brief Fill infer_request tensors with random values or image information
*/
void fillTensors(ov::InferRequest &infer_request, const std::vector<ov::Output<ov::Node>> &inputs) {
for (size_t i = 0; i < inputs.size(); ++i) {
ov::Tensor input_tensor;
if (inputs[i].get_element_type() == ov::element::f32) {
input_tensor = fillTensorRandom<float>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::f16) {
input_tensor = fillTensorRandom<short>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::i32) {
input_tensor = fillTensorRandom<int32_t>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::u8) {
input_tensor = fillTensorRandom<uint8_t>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::i8) {
input_tensor = fillTensorRandom<int8_t>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::u16) {
input_tensor = fillTensorRandom<uint16_t>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::i16) {
input_tensor = fillTensorRandom<int16_t>(inputs[i]);
} else {
throw std::logic_error(
"Input precision is not supported for " + inputs[i].get_element_type().get_type_name());
}
infer_request.set_input_tensor(i, input_tensor);
}
}
}
+46 -17
View File
@@ -5,6 +5,7 @@
#pragma once
#include <inference_engine.hpp>
#include <openvino/openvino.hpp>
#include <limits>
@@ -67,7 +68,7 @@ inline std::pair<size_t, size_t> getTensorHeightWidth(const InferenceEngine::Ten
*/
template<typename T>
void fillBlobRandom(InferenceEngine::Blob::Ptr &inputBlob) {
auto minput = InferenceEngine::as<InferenceEngine::MemoryBlob>(inputBlob);
InferenceEngine::MemoryBlob::Ptr minput = InferenceEngine::as<InferenceEngine::MemoryBlob>(inputBlob);
// locked memory holder should be alive all time while access to its buffer happens
auto minputHolder = minput->wmap();
@@ -78,23 +79,26 @@ void fillBlobRandom(InferenceEngine::Blob::Ptr &inputBlob) {
}
}
/**
* @brief Fill InferenceEngine tensor with random values (OV API 2.0)
*/
template<typename T>
ov::Tensor fillTensorRandom(const ov::Output<ov::Node> &input) {
template<typename T, typename U>
ov::Tensor fillTensorRandom(T &input) {
ov::Tensor tensor{input.get_element_type(), input.get_shape()};
std::vector<T> values(ov::shape_size(input.get_shape()));
for (size_t i = 0; i < values.size(); ++i) {
values[i] = 1 + static_cast <T> (rand()) / (static_cast <T> (RAND_MAX / (std::numeric_limits<T>::max() - 1)));
}
std::memcpy(tensor.data(), values.data(), sizeof(T) * values.size());
std::vector<U> values(ov::shape_size(input.get_shape()));
for (size_t i = 0; i < values.size(); ++i)
values[i] = 1 + static_cast<U> (rand()) / (static_cast<U> (RAND_MAX / (std::numeric_limits<U>::max() - 1)));
std::memcpy(tensor.data(), values.data(), sizeof(U) * values.size());
return tensor;
}
/**
* @brief Fill InferenceEngine blob with image information (OV API 1.0)
* @brief Fill InferenceEngine blob with image information (OV API 1)
*/
template<typename T>
void fillBlobImInfo(InferenceEngine::Blob::Ptr &inputBlob,
@@ -121,14 +125,39 @@ void fillBlobImInfo(InferenceEngine::Blob::Ptr &inputBlob,
/**
* @brief Fill InferRequest blobs with random values or image information
* @brief Fill infer_request tensors with random values (OV API 2)
*/
template<typename T>
void fillTensors(ov::InferRequest &infer_request, std::vector<T> &inputs) {
for (size_t i = 0; i < inputs.size(); ++i) {
ov::Tensor input_tensor;
if (inputs[i].get_element_type() == ov::element::f32) {
input_tensor = fillTensorRandom<T, float>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::f16) {
input_tensor = fillTensorRandom<T, short>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::i32) {
input_tensor = fillTensorRandom<T, int32_t>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::u8) {
input_tensor = fillTensorRandom<T, uint8_t>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::i8) {
input_tensor = fillTensorRandom<T, int8_t>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::u16) {
input_tensor = fillTensorRandom<T, uint16_t>(inputs[i]);
} else if (inputs[i].get_element_type() == ov::element::i16) {
input_tensor = fillTensorRandom<T, int16_t>(inputs[i]);
} else {
throw std::logic_error(
"Input precision is not supported for " + inputs[i].get_element_type().get_type_name());
}
infer_request.set_input_tensor(i, input_tensor);
}
}
/**
* @brief Fill InferRequest blobs with random values or image information (OV API 1)
*/
void fillBlobs(InferenceEngine::InferRequest inferRequest,
const InferenceEngine::ConstInputsDataMap &inputsInfo,
const size_t &batchSize);
/**
* @brief Fill InferRequest tensors with random values or image information
*/
void fillTensors(ov::InferRequest &infer_request,
const std::vector<ov::Output<ov::Node>> &inputs);
const size_t &batchSize);
+120 -55
View File
@@ -1,70 +1,76 @@
// Copyright (C) 2018-2021 Intel Corporation
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "common_utils.h"
#include "reshape_utils.h"
#include <inference_engine.hpp>
using namespace InferenceEngine;
/**
* @brief Parse data shapes for model
*/
std::map<std::string, std::vector<size_t>> parseDataShapes(const std::string& shapeString) {
std::map<std::string, std::vector<size_t>> data_shapes;
// Parse input parameter string
std::vector<std::string> inputsShapes = split(shapeString, '&');
std::map<std::string, std::vector<size_t>> parseDataShapes(const std::string &shapeString) {
std::map<std::string, std::vector<size_t>> data_shapes;
// Parse input parameter string
std::vector<std::string> inputsShapes = split(shapeString, '&');
for (int i = 0; i < inputsShapes.size(); i++) {
std::vector<std::string> curLayout = split(inputsShapes[i], ':');
for (int i = 0; i < inputsShapes.size(); i++) {
std::vector<std::string> curLayout = split(inputsShapes[i], '*');
std::string curLayoutName = curLayout.at(0);
std::vector<size_t> shape;
std::string curLayoutName = curLayout.at(0);
std::vector<size_t> shape;
for (auto& dim : split(curLayout.at(1), ','))
shape.emplace_back(std::stoi(dim));
data_shapes[curLayoutName] = shape;
}
return data_shapes;
try {
for (auto &dim: split(curLayout.at(1), ','))
shape.emplace_back(std::stoi(dim));
} catch (const std::exception &ex) {
std::cerr << "Parsing data shapes failed with exception:\n"
<< ex.what() << "\n";
}
data_shapes[curLayoutName] = shape;
}
return data_shapes;
}
/**
* @brief Parse input shapes for model reshape
*/
std::map<std::string, ov::PartialShape> parseReshapeShapes(const std::string& shapeString) {
std::map<std::string, ov::PartialShape> reshape_info;
// Parse input parameter string
std::vector<std::string> inputsShapes = split(shapeString, '&');
std::map<std::string, ov::PartialShape> parseReshapeShapes(const std::string &shapeString) {
std::map<std::string, ov::PartialShape> reshape_info;
// Parse input parameter string
std::vector<std::string> inputsShapes = split(shapeString, '&');
for (int i = 0; i < inputsShapes.size(); i++) {
std::vector<std::string> curLayout = split(inputsShapes[i], ':');
for (int i = 0; i < inputsShapes.size(); i++) {
std::vector<std::string> curLayout = split(inputsShapes[i], '*');
std::string curLayoutName = curLayout.at(0);
std::vector<ov::Dimension> shape;
std::string curLayoutName = curLayout.at(0);
std::vector<ov::Dimension> shape;
for (auto& dim : split(curLayout.at(1), ',')) {
if (dim == "?" || dim == "-1") {
shape.emplace_back(ov::Dimension::dynamic());
}
else {
const std::string range_divider = "..";
size_t range_index = dim.find(range_divider);
if (range_index != std::string::npos) {
std::string min = dim.substr(0, range_index);
std::string max = dim.substr(range_index + range_divider.length());
shape.emplace_back(ov::Dimension(std::stoi(min), std::stoi(max)));
} else {
shape.emplace_back(ov::Dimension(std::stoi(dim)));
for (auto& dim : split(curLayout.at(1), ',')) {
try {
if (dim == "?" || dim == "-1") {
shape.emplace_back(ov::Dimension::dynamic());
}
else {
const std::string range_divider = "..";
size_t range_index = dim.find(range_divider);
if (range_index != std::string::npos) {
std::string min = dim.substr(0, range_index);
std::string max = dim.substr(range_index + range_divider.length());
shape.emplace_back(ov::Dimension(std::stoi(min), std::stoi(max)));
} else {
shape.emplace_back(ov::Dimension(std::stoi(dim)));
}
}
} catch (const std::exception &ex) {
std::cerr << "Parsing reshape shapes failed with exception:\n"
<< ex.what() << "\n";
}
}
}
reshape_info[curLayoutName] = ov::PartialShape(shape);
}
reshape_info[curLayoutName] = ov::PartialShape(shape);
}
return reshape_info;
return reshape_info;
}
@@ -72,7 +78,7 @@ std::map<std::string, ov::PartialShape> parseReshapeShapes(const std::string& sh
* @brief Split input string using specified delimiter.
Return vector with input tensor information
*/
std::vector<std::string> split(const std::string& s, char delim) {
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> result;
std::stringstream ss(s);
std::string item;
@@ -87,18 +93,77 @@ std::vector<std::string> split(const std::string& s, char delim) {
/**
* @brief Reshape blobs with dynamic shapes with static information from data shape
*/
void setStaticShapesBlobs(InferenceEngine::InferRequest inferRequest,
const InferenceEngine::ConstInputsDataMap& inputsInfo,
void setBlobsStaticShapes(InferenceEngine::InferRequest inferRequest,
const InferenceEngine::ConstInputsDataMap &inputsInfo,
std::map<std::string, std::vector<size_t>> dataShape) {
for (const ConstInputsDataMap::value_type& item : inputsInfo) {
Blob::Ptr inputBlob = inferRequest.GetBlob(item.first);
for (const InferenceEngine::ConstInputsDataMap::value_type &item : inputsInfo) {
InferenceEngine::Blob::Ptr inputBlob = inferRequest.GetBlob(item.first);
if (dataShape.count(item.first)) {
SizeVector newInputShape;
for (size_t i = 0; i < dataShape[item.first].size(); i++) {
newInputShape.emplace_back(dataShape[item.first][i]);
}
inputBlob->setShape(newInputShape);
if (dataShape.count(item.first)) {
InferenceEngine::SizeVector newInputShape;
for (size_t i = 0; i < dataShape[item.first].size(); i++) {
newInputShape.emplace_back(dataShape[item.first][i]);
}
inputBlob->setShape(newInputShape);
}
}
}
/**
* @brief Getting tensor shapes. If tensor is dynamic, static shape from data info will be returned.
*/
ov::Shape getTensorStaticShape(ov::Output<const ov::Node> &input,
std::map<std::string, std::vector<size_t>> dataShape) {
std::string name;
try {
name = input.get_any_name();
} catch (const ov::Exception &iex) {
// Attempt to get a name for a Tensor without names
}
ov::Shape inputShape;
if (!input.get_partial_shape().is_dynamic()) {
return input.get_shape();
}
else if (dataShape.count(name)) {
for (size_t j = 0; j < dataShape[name].size(); j++)
inputShape.emplace_back(dataShape[name][j]);
}
else {
throw std::logic_error("Please provide static shape for " + name + "input using -data_shapes argument!");
}
return inputShape;
}
/**
* @brief Fill infer_request tensors with random values. The model shape is set separately. (OV API 2)
*/
void fillTensorsWithSpecifiedShape(ov::InferRequest& infer_request, std::vector<ov::Output<const ov::Node>> &inputs,
std::map<std::string, std::vector<size_t>> dataShape) {
for (size_t i = 0; i < inputs.size(); i++) {
ov::Tensor input_tensor;
ov::Shape inputShape = getTensorStaticShape(inputs[i], dataShape);
if (inputs[i].get_element_type() == ov::element::f32) {
input_tensor = fillTensorRandomDynamic<float>(inputs[i], inputShape);
} else if (inputs[i].get_element_type() == ov::element::f16) {
input_tensor = fillTensorRandomDynamic<short>(inputs[i], inputShape);
} else if (inputs[i].get_element_type() == ov::element::i32) {
input_tensor = fillTensorRandomDynamic<int32_t>(inputs[i], inputShape);
} else if (inputs[i].get_element_type() == ov::element::u8) {
input_tensor = fillTensorRandomDynamic<uint8_t>(inputs[i], inputShape);
} else if (inputs[i].get_element_type() == ov::element::i8) {
input_tensor = fillTensorRandomDynamic<int8_t>(inputs[i], inputShape);
} else if (inputs[i].get_element_type() == ov::element::u16) {
input_tensor = fillTensorRandomDynamic<uint16_t>(inputs[i], inputShape);
} else if (inputs[i].get_element_type() == ov::element::i16) {
input_tensor = fillTensorRandomDynamic<int16_t>(inputs[i], inputShape);
} else {
throw std::logic_error("Input precision is not supported for " + inputs[i].get_element_type().get_type_name());
}
infer_request.set_input_tensor(i, input_tensor);
}
}
}
+38 -8
View File
@@ -1,36 +1,66 @@
// Copyright (C) 2018-2021 Intel Corporation
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <inference_engine.hpp>
#include <openvino/openvino.hpp>
using namespace InferenceEngine;
/**
* @brief Fill InferenceEngine tensor with random values. The model shape is set separately.
*/
template<typename T>
ov::Tensor fillTensorRandomDynamic(ov::Output<const ov::Node> &input, ov::Shape shape) {
ov::Tensor tensor {input.get_element_type(), shape};
std::vector<T>values(ov::shape_size(shape));
for (size_t i = 0; i < values.size(); ++i) {
values[i] = 1 + static_cast<T>(rand()) / (static_cast<T>(RAND_MAX / (std::numeric_limits<T>::max() - 1)));
}
std::memcpy(tensor.data(), values.data(), sizeof(T) * values.size());
return tensor;
}
/**
* @brief Split input string using specified delimiter.
Return vector with input tensor information
*/
std::vector<std::string> split(const std::string& s, char delim);
std::vector<std::string> split(const std::string &s, char delim);
/**
* @brief Parse input shapes for model reshape
*/
std::map<std::string, ov::PartialShape> parseReshapeShapes(const std::string& shapeString);
std::map<std::string, ov::PartialShape> parseReshapeShapes(const std::string &shapeString);
/**
* @brief Parse data shapes for model
*/
std::map<std::string, std::vector<size_t>> parseDataShapes(const std::string& shapeString);
std::map<std::string, std::vector<size_t>> parseDataShapes(const std::string &shapeString);
/**
* @brief Getting tensor shapes. If tensor is dynamic, static shape from data info will be returned.
*/
ov::Shape getTensorStaticShape(ov::Output<const ov::Node> &input,
std::map<std::string, std::vector<size_t>> dataShape);
/**
* @brief Reshape blobs with dynamic shapes with static information from data shape
*/
void setStaticShapesBlobs(InferenceEngine::InferRequest inferRequest,
const InferenceEngine::ConstInputsDataMap& inputsInfo,
std::map<std::string, std::vector<size_t>> dataShape);
void setBlobsStaticShapes(InferenceEngine::InferRequest inferRequest,
const InferenceEngine::ConstInputsDataMap &inputsInfo,
std::map<std::string, std::vector<size_t>> dataShape);
/**
* @brief Fill infer_request tensors with random values. The model shape is set separately. (OV API 2)
*/
void fillTensorsWithSpecifiedShape(ov::InferRequest& infer_request, std::vector<ov::Output<const ov::Node>> &inputs,
std::map<std::string, std::vector<size_t>> dataShape);
@@ -8,24 +8,24 @@
#include <string>
namespace TimeTest {
using time_point = std::chrono::high_resolution_clock::time_point;
using time_point = std::chrono::high_resolution_clock::time_point;
/** Encapsulate time measurements.
Object of a class measures time at start and finish of object's life cycle.
When destroyed, reports duration.
*/
class Timer {
private:
std::string name;
time_point start_time;
class Timer {
private:
std::string name;
time_point start_time;
public:
/// Constructs Timer object and measures start time.
Timer(const std::string &timer_name);
public:
/// Constructs Timer object and measures start time.
Timer(const std::string &timer_name);
/// Destructs Timer object, measures duration and reports it.
~Timer();
};
/// Destructs Timer object, measures duration and reports it.
~Timer();
};
#define SCOPED_TIMER(timer_name) TimeTest::Timer timer_name(#timer_name);
@@ -5,6 +5,7 @@
#pragma once
#include <inference_engine.hpp>
#include <openvino/openvino.hpp>
#include <ie_plugin_config.hpp>
#include <string>
@@ -22,17 +23,32 @@ std::string fileExt(const std::string &filename) {
}
/**
* @brief Function that enables Latency performance hint for specified device.
* @brief Function that enables Latency performance hint for specified device (OV API 1)
*/
void setPerformanceConfig(InferenceEngine::Core ie, const std::string &device) {
std::vector<std::string> supported_config_keys = ie.GetMetric(device, METRIC_KEY(SUPPORTED_CONFIG_KEYS));
std::vector<std::string> supported_config_keys = ie.GetMetric(device, METRIC_KEY(SUPPORTED_CONFIG_KEYS));
if (std::find(supported_config_keys.begin(), supported_config_keys.end(), "PERFORMANCE_HINT") ==
supported_config_keys.end()) {
std::cerr << "Device " << device << " doesn't support config key 'PERFORMANCE_HINT'!\n"
<< "Performance config was not set.";
}
else
ie.SetConfig({{CONFIG_KEY(PERFORMANCE_HINT), CONFIG_VALUE(LATENCY)}}, device);
if (std::find(supported_config_keys.begin(), supported_config_keys.end(), "PERFORMANCE_HINT") ==
supported_config_keys.end()) {
std::cerr << "Device " << device << " doesn't support config key 'PERFORMANCE_HINT'!\n"
<< "Performance config was not set.";
}
else
ie.SetConfig({{CONFIG_KEY(PERFORMANCE_HINT), CONFIG_VALUE(LATENCY)}}, device);
}
/**
* @brief Function that enables Latency performance hint for specified device (OV API 2)
*/
void setPerformanceConfig(ov::Core ie, const std::string &device) {
std::vector<std::string> supported_config_keys = ie.get_property(device, METRIC_KEY(SUPPORTED_CONFIG_KEYS));
if (std::find(supported_config_keys.begin(), supported_config_keys.end(), "PERFORMANCE_HINT") ==
supported_config_keys.end()) {
std::cerr << "Device " << device << " doesn't support config key 'PERFORMANCE_HINT'!\n"
<< "Performance config was not set.";
}
else
ie.set_property(device, {{CONFIG_KEY(PERFORMANCE_HINT), CONFIG_VALUE(LATENCY)}});
}
}
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//
#include <inference_engine.hpp>
#include <iostream>
#include "common_utils.h"
@@ -10,8 +9,6 @@
#include "timetests_helper/timer.h"
#include "timetests_helper/utils.h"
using namespace InferenceEngine;
/**
* @brief Function that contain executable pipeline which will be called from
@@ -21,96 +18,94 @@ using namespace InferenceEngine;
int runPipeline(const std::string &model, const std::string &device, const bool isCacheEnabled,
std::map<std::string, ov::PartialShape> reshapeShapes,
std::map<std::string, std::vector<size_t>> dataShapes) {
auto pipeline = [](const std::string &model, const std::string &device, const bool isCacheEnabled,
std::map<std::string, ov::PartialShape> reshapeShapes,
std::map<std::string, std::vector<size_t>> dataShapes) {
Core ie;
CNNNetwork cnnNetwork;
ExecutableNetwork exeNetwork;
InferRequest inferRequest;
size_t batchSize = 0;
auto pipeline = [](const std::string &model, const std::string &device, const bool isCacheEnabled,
std::map<std::string, ov::PartialShape> reshapeShapes,
std::map<std::string, std::vector<size_t>> dataShapes) {
InferenceEngine::Core ie;
InferenceEngine::CNNNetwork cnnNetwork;
InferenceEngine::ExecutableNetwork exeNetwork;
InferenceEngine::InferRequest inferRequest;
size_t batchSize = 0;
bool reshape = false;
if (!reshapeShapes.empty()) {
reshape = true;
}
bool reshape = false;
if (!reshapeShapes.empty()) {
reshape = true;
}
// first_inference_latency = time_to_inference + first_inference
{
SCOPED_TIMER(time_to_inference);
{
SCOPED_TIMER(load_plugin);
ie.GetVersions(device);
}
// Set performance and model cache configs
TimeTest::setPerformanceConfig(ie, device);
if (isCacheEnabled)
ie.SetConfig({{CONFIG_KEY(CACHE_DIR), "models_cache"}});
{
SCOPED_TIMER(create_exenetwork);
if (!isCacheEnabled) {
if (TimeTest::fileExt(model) == "blob") {
SCOPED_TIMER(import_network);
exeNetwork = ie.ImportNetwork(model, device);
}
else {
// first_inference_latency = time_to_inference + first_inference
{
SCOPED_TIMER(time_to_inference);
{
SCOPED_TIMER(read_network);
cnnNetwork = ie.ReadNetwork(model);
batchSize = cnnNetwork.getBatchSize();
}
if (reshape) {
{
SCOPED_TIMER(reshape);
cnnNetwork.reshape(reshapeShapes);
}
SCOPED_TIMER(load_plugin);
TimeTest::setPerformanceConfig(ie, device);
ie.GetVersions(device);
if (isCacheEnabled)
ie.SetConfig({{CONFIG_KEY(CACHE_DIR), "models_cache"}});
}
{
SCOPED_TIMER(load_network);
exeNetwork = ie.LoadNetwork(cnnNetwork, device);
SCOPED_TIMER(create_exenetwork);
if (!isCacheEnabled) {
if (TimeTest::fileExt(model) == "blob") {
SCOPED_TIMER(import_network);
exeNetwork = ie.ImportNetwork(model, device);
}
else {
{
SCOPED_TIMER(read_network);
cnnNetwork = ie.ReadNetwork(model);
batchSize = cnnNetwork.getBatchSize();
}
if (reshape) {
{
SCOPED_TIMER(reshape);
cnnNetwork.reshape(reshapeShapes);
}
}
{
SCOPED_TIMER(load_network);
exeNetwork = ie.LoadNetwork(cnnNetwork, device);
}
}
}
else {
SCOPED_TIMER(load_network_cache);
exeNetwork = ie.LoadNetwork(model, device);
}
}
}
inferRequest = exeNetwork.CreateInferRequest();
}
else {
SCOPED_TIMER(load_network_cache);
exeNetwork = ie.LoadNetwork(model, device);
{
SCOPED_TIMER(first_inference);
{
SCOPED_TIMER(fill_inputs);
const InferenceEngine::ConstInputsDataMap inputsInfo(exeNetwork.GetInputsInfo());
batchSize = batchSize != 0 ? batchSize : 1;
if (reshape) {
setBlobsStaticShapes(inferRequest, inputsInfo, dataShapes);
fillBlobs(inferRequest, inputsInfo, batchSize);
} else {
fillBlobs(inferRequest, inputsInfo, batchSize);
}
}
inferRequest.Infer();
}
}
inferRequest = exeNetwork.CreateInferRequest();
};
try {
pipeline(model, device, isCacheEnabled, reshapeShapes, dataShapes);
} catch (const InferenceEngine::Exception &iex) {
std::cerr
<< "Inference Engine pipeline failed with Inference Engine exception:\n"
<< iex.what();
return 1;
} catch (const std::exception &ex) {
std::cerr << "Inference Engine pipeline failed with exception:\n"
<< ex.what();
return 2;
} catch (...) {
std::cerr << "Inference Engine pipeline failed\n";
return 3;
}
{
SCOPED_TIMER(first_inference);
{
SCOPED_TIMER(fill_inputs);
const InferenceEngine::ConstInputsDataMap inputsInfo(exeNetwork.GetInputsInfo());
batchSize = batchSize != 0 ? batchSize : 1;
if (reshape) {
setStaticShapesBlobs(inferRequest, inputsInfo, dataShapes);
fillBlobs(inferRequest, inputsInfo, batchSize);
} else {
fillBlobs(inferRequest, inputsInfo, batchSize);
}
}
inferRequest.Infer();
}
};
try {
pipeline(model, device, isCacheEnabled, reshapeShapes, dataShapes);
} catch (const InferenceEngine::Exception &iex) {
std::cerr
<< "Inference Engine pipeline failed with Inference Engine exception:\n"
<< iex.what();
return 1;
} catch (const std::exception &ex) {
std::cerr << "Inference Engine pipeline failed with exception:\n"
<< ex.what();
return 2;
} catch (...) {
std::cerr << "Inference Engine pipeline failed\n";
return 3;
}
return 0;
return 0;
}
@@ -0,0 +1,109 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <openvino/runtime/core.hpp>
#include <fstream>
#include "common_utils.h"
#include "reshape_utils.h"
#include "timetests_helper/timer.h"
#include "timetests_helper/utils.h"
/**
* @brief Function that contain executable pipeline which will be called from
* main(). The function should not throw any exceptions and responsible for
* handling it by itself.
*/
int runPipeline(const std::string &model, const std::string &device, const bool isCacheEnabled,
std::map<std::string, ov::PartialShape> reshapeShapes,
std::map<std::string, std::vector<size_t>> dataShapes) {
auto pipeline = [](const std::string &model, const std::string &device, const bool isCacheEnabled,
std::map<std::string, ov::PartialShape> reshapeShapes,
std::map<std::string, std::vector<size_t>> dataShapes) {
ov::Core ie;
std::shared_ptr<ov::Model> cnnNetwork;
ov::CompiledModel exeNetwork;
ov::InferRequest inferRequest;
bool reshape = false;
if (!reshapeShapes.empty()) {
reshape = true;
}
// first_inference_latency = time_to_inference + first_inference
{
SCOPED_TIMER(time_to_inference);
{
SCOPED_TIMER(load_plugin);
TimeTest::setPerformanceConfig(ie, device);
ie.get_versions(device);
if (isCacheEnabled)
ie.set_property({{CONFIG_KEY(CACHE_DIR), "models_cache"}});
}
{
SCOPED_TIMER(create_exenetwork);
if (!isCacheEnabled) {
if (TimeTest::fileExt(model) == "blob") {
SCOPED_TIMER(import_network);
std::ifstream streamModel{model};
exeNetwork = ie.import_model(streamModel, device);
}
else {
{
SCOPED_TIMER(read_network);
cnnNetwork = ie.read_model(model);
}
if (reshape) {
{
SCOPED_TIMER(reshape);
cnnNetwork->reshape(reshapeShapes);
}
}
{
SCOPED_TIMER(load_network);
exeNetwork = ie.compile_model(cnnNetwork, device);
}
}
}
else {
SCOPED_TIMER(load_network_cache);
exeNetwork = ie.compile_model(model, device);
}
}
inferRequest = exeNetwork.create_infer_request();
}
{
SCOPED_TIMER(first_inference);
{
SCOPED_TIMER(fill_inputs);
std::vector<ov::Output<const ov::Node>> inputs = exeNetwork.inputs();
if (reshape) {
fillTensorsWithSpecifiedShape(inferRequest, inputs,dataShapes);
} else {
fillTensors(inferRequest, inputs);
}
}
inferRequest.infer();
}
};
try {
pipeline(model, device, isCacheEnabled, reshapeShapes, dataShapes);
} catch (const ov::Exception &iex) {
std::cerr
<< "Inference Engine pipeline failed with Inference Engine exception:\n"
<< iex.what();
return 1;
} catch (const std::exception &ex) {
std::cerr << "Inference Engine pipeline failed with exception:\n"
<< ex.what();
return 2;
} catch (...) {
std::cerr << "Inference Engine pipeline failed\n";
return 3;
}
return 0;
}
+27 -27
View File
@@ -11,40 +11,40 @@
/// @brief message for help argument
static const char help_message[] =
"Print a usage message.";
"Print a usage message.";
/// @brief message for model argument
static const char model_message[] =
"Required. Path to an .xml/.onnx file with a trained model or to "
"a .blob files with a trained compiled model.";
"Required. Path to an .xml/.onnx file with a trained model or to "
"a .blob files with a trained compiled model.";
/// @brief message for target device argument
static const char target_device_message[] =
"Required. Specify a target device to infer on. \n"
"Use \"-d HETERO:<comma-separated_devices_list>\" format to specify HETERO "
"plugin. \n"
"Use \"-d MULTI:<comma-separated_devices_list>\" format to specify MULTI "
"plugin. \n"
"The application looks for a suitable plugin for the specified device.";
"Required. Specify a target device to infer on. \n"
"Use \"-d HETERO:<comma-separated_devices_list>\" format to specify HETERO "
"plugin. \n"
"Use \"-d MULTI:<comma-separated_devices_list>\" format to specify MULTI "
"plugin. \n"
"The application looks for a suitable plugin for the specified device.";
/// @brief message for cache argument
static const char model_cache_message[] =
"Not required. Use this key to run timetests with models caching. \n"
"TimeInfer executable should be run twice - the second run will use cache prepared from first run.";
"Not required. Use this key to run timetests with models caching. \n"
"TimeInfer executable should be run twice - the second run will use cache prepared from first run.";
/// @brief message for shapes argument
static const char reshape_shapes_message[] =
"Not required. Use this key to run timetests with reshape. \n"
"Example: 'input:1..2 3 100 100'. Use '&' delimiter for several inputs. Example: 'input1:1..2 100&input2:1..2 100' ";
"Not required. Use this key to run timetests with reshape. \n"
"Example: 'input*1..2 3 100 100'. Use '&' delimiter for several inputs. Example: 'input1*1..2 100&input2*1..2 100' ";
/// @brief message for shapes argument
static const char data_shapes_message[] =
"Not required. Use this key to run timetests with reshape. Used with 'reshape_shapes' arg. \n"
"Only static shapes for data. Example: 'input:1 3 100 100'. Use '&' delimiter for several inputs. Example: 'input1:1 100&input2:1 100' ";
"Not required. Use this key to run timetests with reshape. Used with 'reshape_shapes' arg. \n"
"Only static shapes for data. Example: 'input*1 3 100 100'. Use '&' delimiter for several inputs. Example: 'input1*1 100&input2*1 100' ";
/// @brief message for statistics path argument
static const char statistics_path_message[] =
"Required. Path to a file to write statistics.";
"Required. Path to a file to write statistics.";
/// @brief Define flag for showing help message <br>
DEFINE_bool(h, false, help_message);
@@ -80,15 +80,15 @@ DEFINE_string(s, "", statistics_path_message);
* @brief This function show a help message
*/
static void showUsage() {
std::cout << std::endl;
std::cout << "TimeInfer [OPTION]" << std::endl;
std::cout << "Options:" << std::endl;
std::cout << std::endl;
std::cout << " -h, --help " << help_message << std::endl;
std::cout << " -m \"<path>\" " << model_message << std::endl;
std::cout << " -d \"<device>\" " << target_device_message << std::endl;
std::cout << " -s \"<path>\" " << statistics_path_message << std::endl;
std::cout << " -c " << model_cache_message << std::endl;
std::cout << " -reshape_shapes " << reshape_shapes_message << std::endl;
std::cout << " -data_shapes " << data_shapes_message << std::endl;
std::cout << std::endl;
std::cout << "TimeInfer [OPTION]" << std::endl;
std::cout << "Options:" << std::endl;
std::cout << std::endl;
std::cout << " -h, --help " << help_message << std::endl;
std::cout << " -m \"<path>\" " << model_message << std::endl;
std::cout << " -d \"<device>\" " << target_device_message << std::endl;
std::cout << " -s \"<path>\" " << statistics_path_message << std::endl;
std::cout << " -c " << model_cache_message << std::endl;
std::cout << " -reshape_shapes " << reshape_shapes_message << std::endl;
std::cout << " -data_shapes " << data_shapes_message << std::endl;
}
+28 -28
View File
@@ -18,29 +18,29 @@ int runPipeline(const std::string &model, const std::string &device, const bool
* @brief Parses command line and check required arguments
*/
bool parseAndCheckCommandLine(int argc, char **argv) {
gflags::ParseCommandLineNonHelpFlags(&argc, &argv, true);
if (FLAGS_help || FLAGS_h) {
showUsage();
return false;
}
gflags::ParseCommandLineNonHelpFlags(&argc, &argv, true);
if (FLAGS_help || FLAGS_h) {
showUsage();
return false;
}
if (FLAGS_m.empty())
throw std::logic_error(
"Model is required but not set. Please set -m option.");
if (FLAGS_m.empty())
throw std::logic_error(
"Model is required but not set. Please set -m option.");
if (FLAGS_d.empty())
throw std::logic_error(
"Device is required but not set. Please set -d option.");
if (FLAGS_d.empty())
throw std::logic_error(
"Device is required but not set. Please set -d option.");
if (FLAGS_s.empty())
throw std::logic_error(
"Statistics file path is required but not set. Please set -s option.");
if (FLAGS_s.empty())
throw std::logic_error(
"Statistics file path is required but not set. Please set -s option.");
if (!FLAGS_reshape_shapes.empty() && FLAGS_data_shapes.empty())
throw std::logic_error(
"Data shapes is required for reshape shapes argument. Please set -data_shapes option.");
if (!FLAGS_reshape_shapes.empty() && FLAGS_data_shapes.empty())
throw std::logic_error(
"Data shapes is required for reshape shapes argument. Please set -data_shapes option.");
return true;
return true;
}
/**
@@ -48,22 +48,22 @@ bool parseAndCheckCommandLine(int argc, char **argv) {
*/
int _runPipeline(std::map<std::string, ov::PartialShape> dynamicShapes,
std::map<std::string, std::vector<size_t>> staticShapes) {
SCOPED_TIMER(full_run);
return runPipeline(FLAGS_m, FLAGS_d, FLAGS_c, dynamicShapes, staticShapes);
SCOPED_TIMER(full_run);
return runPipeline(FLAGS_m, FLAGS_d, FLAGS_c, dynamicShapes, staticShapes);
}
/**
* @brief Main entry point
*/
int main(int argc, char **argv) {
if (!parseAndCheckCommandLine(argc, argv))
return -1;
if (!parseAndCheckCommandLine(argc, argv))
return -1;
auto dynamicShapes = parseReshapeShapes(FLAGS_reshape_shapes);
auto staticShapes = parseDataShapes(FLAGS_data_shapes);
auto dynamicShapes = parseReshapeShapes(FLAGS_reshape_shapes);
auto staticShapes = parseDataShapes(FLAGS_data_shapes);
auto status = _runPipeline(dynamicShapes, staticShapes);
StatisticsWriter::Instance().setFile(FLAGS_s);
StatisticsWriter::Instance().write();
return status;
auto status = _runPipeline(dynamicShapes, staticShapes);
StatisticsWriter::Instance().setFile(FLAGS_s);
StatisticsWriter::Instance().write();
return status;
}
@@ -22,62 +22,62 @@
*/
class StatisticsWriter {
private:
std::ofstream statistics_file;
std::ofstream statistics_file;
std::map<std::string, std::pair<int, float>> time_structure; // timer_name, <tab number, duration>
std::vector<std::string> time_struct_order;
int tab_count = 0;
std::map<std::string, std::pair<int, float>> time_structure; // timer_name, <tab number, duration>
std::vector<std::string> time_struct_order;
int tab_count = 0;
StatisticsWriter() = default;
StatisticsWriter(const StatisticsWriter &) = delete;
StatisticsWriter &operator=(const StatisticsWriter &) = delete;
StatisticsWriter() = default;
StatisticsWriter(const StatisticsWriter &) = delete;
StatisticsWriter &operator=(const StatisticsWriter &) = delete;
public:
/**
* @brief Creates StatisticsWriter singleton object
*/
static StatisticsWriter &Instance() {
/**
* @brief Creates StatisticsWriter singleton object
*/
static StatisticsWriter &Instance() {
static StatisticsWriter writer;
return writer;
}
}
/**
* @brief Specifies, opens and validates statistics path for writing
*/
void setFile(const std::string &statistics_path) {
/**
* @brief Specifies, opens and validates statistics path for writing
*/
void setFile(const std::string &statistics_path) {
statistics_file.open(statistics_path);
if (!statistics_file.good()) {
std::stringstream err;
err << "Statistic file \"" << statistics_path
<< "\" can't be used for writing";
throw std::runtime_error(err.str());
std::stringstream err;
err << "Statistic file \"" << statistics_path
<< "\" can't be used for writing";
throw std::runtime_error(err.str());
}
}
}
/**
* @brief Compute order for statistics operations.
*/
void addTimer(const std::string name) {
/**
* @brief Compute order for statistics operations.
*/
void addTimer(const std::string name) {
time_struct_order.push_back(name);
tab_count++;
}
}
void deleteTimer(const std::pair<std::string, float> &record) {
void deleteTimer(const std::pair<std::string, float> &record) {
tab_count--;
time_structure[record.first] = std::make_pair(tab_count, record.second);
}
}
/**
* @brief Writes provided statistics in YAML format.
*/
void write() {
/**
* @brief Writes provided statistics in YAML format.
*/
void write() {
if (!statistics_file)
throw std::runtime_error("Statistic file path isn't set");
throw std::runtime_error("Statistic file path isn't set");
for (auto& timer: time_struct_order) {
std::string tabs = std::string(TAB* time_structure[timer].first, ' ');
statistics_file << tabs << "- " << timer << ":" << '\n'
<< tabs << " " << "- " << time_structure[timer].second << '\n';
std::string tabs = std::string(TAB* time_structure[timer].first, ' ');
statistics_file << tabs << "- " << timer << ":" << '\n'
<< tabs << " " << "- " << time_structure[timer].second << '\n';
}
statistics_file << "---" << '\n' << "measurement_unit: microsecs";
}
}
};
@@ -14,18 +14,17 @@ using time_point = std::chrono::high_resolution_clock::time_point;
namespace TimeTest {
Timer::Timer(const std::string &timer_name) {
name = timer_name;
start_time = std::chrono::high_resolution_clock::now();
StatisticsWriter::Instance().addTimer(name);
name = timer_name;
start_time = std::chrono::high_resolution_clock::now();
StatisticsWriter::Instance().addTimer(name);
}
Timer::~Timer() {
float duration = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now() - start_time)
.count();
StatisticsWriter::Instance().deleteTimer({name, duration});
float duration = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now() - start_time)
.count();
StatisticsWriter::Instance().deleteTimer({name, duration});
}
} // namespace TimeTest