openvino/docs/template_plugin/src/template_infer_request.cpp

323 lines
13 KiB
C++

// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "template_infer_request.hpp"
#include <algorithm>
#include <map>
#include <memory>
#include <ngraph/runtime/reference/convert.hpp>
#include <string>
#include <utility>
#include "blob_factory.hpp"
#include "ie_ngraph_utils.hpp"
#include "template_executable_network.hpp"
#include "template_itt.hpp"
#include "template_plugin.hpp"
using namespace TemplatePlugin;
using namespace InferenceEngine;
using Time = std::chrono::high_resolution_clock;
// ! [infer_request:ctor]
TemplateInferRequest::TemplateInferRequest(const InferenceEngine::InputsDataMap& networkInputs,
const InferenceEngine::OutputsDataMap& networkOutputs,
const std::shared_ptr<TemplatePlugin::ExecutableNetwork>& executableNetwork)
: IInferRequestInternal(networkInputs, networkOutputs),
_executableNetwork(executableNetwork) {
// TODO: allocate infer request device and host buffers if needed, fill actual list of profiling tasks
auto requestID = std::to_string(_executableNetwork->_requestId.fetch_add(1));
std::string name = _executableNetwork->_function->get_friendly_name() + "_Req" + requestID;
_profilingTask = {
openvino::itt::handle("Template" + std::to_string(_executableNetwork->_cfg.deviceId) + "_" + name +
"_Preprocess"),
openvino::itt::handle("Template" + std::to_string(_executableNetwork->_cfg.deviceId) + "_" + name +
"_Postprocess"),
openvino::itt::handle("Template" + std::to_string(_executableNetwork->_cfg.deviceId) + "_" + name +
"_StartPipline"),
openvino::itt::handle("Template" + std::to_string(_executableNetwork->_cfg.deviceId) + "_" + name +
"_WaitPipline"),
};
_executable = _executableNetwork->_plugin->_backend->compile(_executableNetwork->_function);
_parameters = _executableNetwork->_function->get_parameters();
_results = _executableNetwork->_function->get_results();
allocateDeviceBuffers();
allocateBlobs();
}
// ! [infer_request:ctor]
// ! [infer_request:dtor]
TemplateInferRequest::~TemplateInferRequest() {
_executableNetwork->_requestId--;
}
// ! [infer_request:dtor]
void TemplateInferRequest::allocateDeviceBuffers() {
// Allocate plugin backend specific memory handles
_inputTensors.resize(_networkInputs.size());
_outputTensors.resize(_networkOutputs.size());
}
template <typename BlobDataMap, typename GetNetworkPrecisionF>
static void AllocateImpl(const BlobDataMap& userDataMap,
BlobMap& userBlobMap,
BlobMap& deviceBlobMap,
GetNetworkPrecisionF&& GetNetworkPrecision,
bool isInputBlob = true) {
for (auto&& userData : userDataMap) {
const auto& dims = userData.second->getTensorDesc().getDims();
const auto deviceLayout = TensorDesc::getLayoutByDims(dims);
const auto userPrecision = userData.second->getTensorDesc().getPrecision();
const auto userLayout = userData.second->getTensorDesc().getLayout();
const auto networkPrecision = InferenceEngine::details::convertPrecision(GetNetworkPrecision(userData.first));
Blob::Ptr userBlob = make_blob_with_precision({userPrecision, dims, userLayout});
userBlob->allocate();
userBlobMap[userData.first] = userBlob;
Blob::Ptr deviceBlob;
if (userPrecision == networkPrecision && userLayout == deviceLayout) {
deviceBlob = userBlob;
} else {
if (userLayout != deviceLayout && !isInputBlob) {
IE_THROW(NotImplemented) << "Template Plugin: does not support setLayout for outputs";
}
deviceBlob = make_blob_with_precision({networkPrecision, dims, deviceLayout});
deviceBlob->allocate();
}
deviceBlobMap[userData.first] = deviceBlob;
}
}
void TemplateInferRequest::allocateBlobs() {
auto&& parameters = _executableNetwork->_function->get_parameters();
AllocateImpl(_networkInputs, _inputs, _deviceInputs, [&](const std::string& blobName) {
return parameters.at(_executableNetwork->_inputIndex.at(blobName))->get_element_type();
});
auto&& results = _executableNetwork->_function->get_results();
AllocateImpl(
_networkOutputs,
_outputs,
_networkOutputBlobs,
[&](const std::string& blobName) {
return results.at(_executableNetwork->_outputIndex.at(blobName))->get_element_type();
},
false);
}
// ! [infer_request:infer_impl]
void TemplateInferRequest::InferImpl() {
// TODO: fill with actual list of pipeline stages, which are executed synchronously for sync infer requests
inferPreprocess();
startPipeline();
waitPipeline(); // does nothing in current implementation
inferPostprocess();
}
// ! [infer_request:infer_impl]
template <typename SrcT, typename DstT>
static void blobCopy(const Blob::Ptr& src, const Blob::Ptr& dst) {
ngraph::runtime::reference::convert<SrcT, DstT>(
InferenceEngine::as<InferenceEngine::MemoryBlob>(src)->rmap().as<const SrcT*>(),
InferenceEngine::as<InferenceEngine::MemoryBlob>(dst)->wmap().as<DstT*>(),
src->size());
}
static void blobCopy(const Blob::Ptr& src, const Blob::Ptr& dst) {
switch (src->getTensorDesc().getPrecision()) {
case Precision::U8: {
switch (dst->getTensorDesc().getPrecision()) {
case Precision::U8:
break;
case Precision::FP32: {
blobCopy<std::uint8_t, float>(src, dst);
} break;
default: {
IE_THROW(NotImplemented) << "Unsupported precision conversion from " << src->getTensorDesc().getPrecision()
<< " to " << dst->getTensorDesc().getPrecision();
}
}
} break;
case Precision::FP32: {
switch (dst->getTensorDesc().getPrecision()) {
case Precision::FP32:
break;
case Precision::U8: {
blobCopy<float, std::uint8_t>(src, dst);
} break;
default: {
IE_THROW(NotImplemented) << "Unsupported precision conversion from " << src->getTensorDesc().getPrecision()
<< " to " << dst->getTensorDesc().getPrecision();
}
}
} break;
case Precision::I64: {
switch (dst->getTensorDesc().getPrecision()) {
case Precision::I64:
break;
case Precision::I32: {
blobCopy<int64_t, int32_t>(src, dst);
} break;
default: {
IE_THROW(NotImplemented) << "Unsupported precision conversion from " << src->getTensorDesc().getPrecision()
<< " to " << dst->getTensorDesc().getPrecision();
}
}
} break;
case Precision::I16: {
switch (dst->getTensorDesc().getPrecision()) {
case Precision::I16:
break;
case Precision::FP32: {
blobCopy<int16_t, float>(src, dst);
} break;
default: {
IE_THROW(NotImplemented) << "Unsupported precision conversion from " << src->getTensorDesc().getPrecision()
<< " to " << dst->getTensorDesc().getPrecision();
}
}
} break;
case Precision::I8: {
switch (dst->getTensorDesc().getPrecision()) {
case Precision::I8:
break;
case Precision::FP32: {
blobCopy<int8_t, float>(src, dst);
} break;
default: {
IE_THROW(NotImplemented) << "Unsupported precision conversion from " << src->getTensorDesc().getPrecision()
<< " to " << dst->getTensorDesc().getPrecision();
}
}
} break;
case Precision::BOOL: {
switch (dst->getTensorDesc().getPrecision()) {
case Precision::BOOL:
break;
case Precision::FP32: {
blobCopy<bool, float>(src, dst);
} break;
default: {
IE_THROW(NotImplemented) << "Unsupported precision conversion from " << src->getTensorDesc().getPrecision()
<< " to " << dst->getTensorDesc().getPrecision();
}
}
} break;
case Precision::U16: {
switch (dst->getTensorDesc().getPrecision()) {
case Precision::U16:
break;
case Precision::FP32: {
blobCopy<uint16_t, float>(src, dst);
} break;
default: {
IE_THROW(NotImplemented) << "Unsupported precision conversion from " << src->getTensorDesc().getPrecision()
<< " to " << dst->getTensorDesc().getPrecision();
}
}
} break;
default: {
IE_THROW(NotImplemented) << "Unsupported precision conversion from " << src->getTensorDesc().getPrecision();
}
}
}
// ! [infer_request:infer_preprocess]
void TemplateInferRequest::inferPreprocess() {
OV_ITT_SCOPED_TASK(itt::domains::TemplatePlugin, _profilingTask[Preprocess]);
auto start = Time::now();
// NOTE: After IInferRequestInternal::execDataPreprocessing call
// input can points to other memory region than it was allocated in constructor.
IInferRequestInternal::execDataPreprocessing(_deviceInputs);
for (auto&& networkInput : _deviceInputs) {
auto index = _executableNetwork->_inputIndex[networkInput.first];
const auto& parameter = _parameters[index];
const auto& parameterShape = parameter->get_shape();
const auto& parameterType = parameter->get_element_type();
_inputTensors[index] = _executableNetwork->_plugin->_backend->create_tensor(
parameterType,
parameterShape,
InferenceEngine::as<InferenceEngine::MemoryBlob>(networkInput.second)->rmap().as<void*>());
}
for (auto&& output : _outputs) {
auto outputBlob = output.second;
auto networkOutput = _networkOutputBlobs[output.first];
auto index = _executableNetwork->_outputIndex[output.first];
if (outputBlob->getTensorDesc().getPrecision() == networkOutput->getTensorDesc().getPrecision()) {
networkOutput = outputBlob;
}
const auto& result = _results[index];
const auto& resultShape = result->get_shape();
const auto& resultType = result->get_element_type();
_outputTensors[index] = _executableNetwork->_plugin->_backend->create_tensor(
resultType,
resultShape,
InferenceEngine::as<InferenceEngine::MemoryBlob>(networkOutput)->wmap().as<void*>());
}
_durations[Preprocess] = Time::now() - start;
}
// ! [infer_request:infer_preprocess]
// ! [infer_request:start_pipeline]
void TemplateInferRequest::startPipeline() {
OV_ITT_SCOPED_TASK(itt::domains::TemplatePlugin, _profilingTask[StartPipeline])
auto start = Time::now();
_executable->call(_outputTensors, _inputTensors);
_durations[StartPipeline] = Time::now() - start;
}
// ! [infer_request:start_pipeline]
void TemplateInferRequest::waitPipeline() {
OV_ITT_SCOPED_TASK(itt::domains::TemplatePlugin, _profilingTask[WaitPipeline])
auto start = Time::now();
// TODO: Wait pipeline using driver API or other synchronizations methods
// NOTE: not used in current implementation since `startPipeline` executes pipiline synchronously
_durations[WaitPipeline] = Time::now() - start;
}
// ! [infer_request:infer_postprocess]
void TemplateInferRequest::inferPostprocess() {
OV_ITT_SCOPED_TASK(itt::domains::TemplatePlugin, _profilingTask[Postprocess]);
auto start = Time::now();
for (auto&& output : _outputs) {
auto outputBlob = output.second;
auto networkOutput = _networkOutputBlobs[output.first];
// perform precision conversion of network output's precision and computational
// graph output's precision are different
if (outputBlob->getTensorDesc().getPrecision() != networkOutput->getTensorDesc().getPrecision()) {
blobCopy(networkOutput, outputBlob);
}
}
_durations[Postprocess] = Time::now() - start;
}
// ! [infer_request:infer_postprocess]
// ! [infer_request:get_performance_counts]
std::map<std::string, InferenceEngineProfileInfo> TemplateInferRequest::GetPerformanceCounts() const {
std::map<std::string, InferenceEngineProfileInfo> perfMap;
InferenceEngineProfileInfo info;
info.execution_index = 0;
info.status = InferenceEngineProfileInfo::EXECUTED;
info.cpu_uSec = info.realTime_uSec = _durations[Preprocess].count();
perfMap["1. input preprocessing"] = info;
info.cpu_uSec = info.realTime_uSec = 0;
perfMap["2. input transfer to a device"] = info;
info.cpu_uSec = info.realTime_uSec = _durations[StartPipeline].count();
perfMap["3. execution time"] = info;
info.cpu_uSec = info.realTime_uSec = 0;
perfMap["4. output transfer from a device"] = info;
info.cpu_uSec = info.realTime_uSec = _durations[Postprocess].count();
perfMap["5. output postprocessing"] = info;
return perfMap;
}
// ! [infer_request:get_performance_counts]