Files
openvino/inference-engine/src/inference_engine/threading/ie_executor_manager.cpp
2020-06-02 21:59:45 +03:00

135 lines
4.6 KiB
C++

// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <memory>
#include <string>
#include <utility>
#include "threading/ie_executor_manager.hpp"
#include "threading/ie_cpu_streams_executor.hpp"
namespace InferenceEngine {
ITaskExecutor::Ptr ExecutorManagerImpl::getExecutor(std::string id) {
std::lock_guard<std::mutex> guard(taskExecutorMutex);
auto foundEntry = executors.find(id);
if (foundEntry == executors.end()) {
auto newExec = std::make_shared<CPUStreamsExecutor>(IStreamsExecutor::Config{id});
executors[id] = newExec;
return newExec;
}
return foundEntry->second;
}
IStreamsExecutor::Ptr ExecutorManagerImpl::getIdleCPUStreamsExecutor(const IStreamsExecutor::Config& config) {
std::lock_guard<std::mutex> guard(streamExecutorMutex);
for (const auto& it : cpuStreamsExecutors) {
const auto& executor = it.second;
if (executor.use_count() != 1)
continue;
const auto& executorConfig = it.first;
if (executorConfig._name == config._name &&
executorConfig._streams == config._streams &&
executorConfig._threadsPerStream == config._threadsPerStream &&
executorConfig._threadBindingType == config._threadBindingType &&
executorConfig._threadBindingStep == config._threadBindingStep &&
executorConfig._threadBindingOffset == config._threadBindingOffset)
return executor;
}
auto newExec = std::make_shared<CPUStreamsExecutor>(config);
cpuStreamsExecutors.emplace_back(std::make_pair(config, newExec));
return newExec;
}
// for tests purposes
size_t ExecutorManagerImpl::getExecutorsNumber() {
return executors.size();
}
// for tests purposes
size_t ExecutorManagerImpl::getIdleCPUStreamsExecutorsNumber() {
return cpuStreamsExecutors.size();
}
void ExecutorManagerImpl::clear(const std::string& id) {
std::lock_guard<std::mutex> stream_guard(streamExecutorMutex);
std::lock_guard<std::mutex> task_guard(taskExecutorMutex);
if (id.empty()) {
executors.clear();
cpuStreamsExecutors.clear();
} else {
executors.erase(id);
cpuStreamsExecutors.erase(
std::remove_if(cpuStreamsExecutors.begin(), cpuStreamsExecutors.end(),
[&](const std::pair<IStreamsExecutor::Config, IStreamsExecutor::Ptr>& it) {
return it.first._name == id;
}),
cpuStreamsExecutors.end());
}
}
std::mutex ExecutorManager::_mutex;
ExecutorManager* ExecutorManager::_instance = nullptr;
ExecutorManager* ExecutorManager::getInstance() {
/*
* 1) We do not use singleton implementation via STATIC LOCAL object like
*
* getInstance() {
* static ExecutorManager _instance;
* return &instance;
* }
*
* Because of problem with destruction order on program exit.
* Some IE classes like MKLDNN::Engine use this singleton in destructor.
* But they has no direct dependency from c++ runtime point of view and
* it's possible that _instance local static variable will be destroyed
* before MKLDNN::~Engine call. Any further manipulation with destroyed
* object will lead to exception or crashes.
*
* 2) We do not use singleton implementation via STATIC object like:
*
* ExecutorManager ExecutorManager::_instance;
* getInstance() {
* return &instance;
* }
*
* Because of problem with double destruction. In some test cases we use
* double link with IE module via static and dynamic version. Both modules
* have static object with same export name and it leads to double construction
* and double destruction of that object. For some c++ compilers (ex gcc 5.4)
* it lead to crash with "double free".
*
* That's why we use manual allocation of singleton instance on heap.
*/
std::lock_guard<std::mutex> guard(_mutex);
if (_instance == nullptr) {
_instance = new ExecutorManager();
}
return _instance;
}
ITaskExecutor::Ptr ExecutorManager::getExecutor(std::string id) {
return _impl.getExecutor(id);
}
size_t ExecutorManager::getExecutorsNumber() {
return _impl.getExecutorsNumber();
}
size_t ExecutorManager::getIdleCPUStreamsExecutorsNumber() {
return _impl.getIdleCPUStreamsExecutorsNumber();
}
void ExecutorManager::clear(const std::string& id) {
_impl.clear(id);
}
IStreamsExecutor::Ptr ExecutorManager::getIdleCPUStreamsExecutor(const IStreamsExecutor::Config& config) {
return _impl.getIdleCPUStreamsExecutor(config);
}
} // namespace InferenceEngine