blob: 7d1a9faaeaedca599df98f3d722c7f39f3e49994 [file] [log] [blame]
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//
#include "Runtime.hpp"
#include "armnn/Version.hpp"
#include <iostream>
#ifdef ARMCOMPUTECL_ENABLED
#include <arm_compute/core/CL/OpenCL.h>
#include <arm_compute/core/CL/CLKernelLibrary.h>
#include <arm_compute/runtime/CL/CLScheduler.h>
#endif
#include <boost/log/trivial.hpp>
#include <boost/polymorphic_cast.hpp>
using namespace armnn;
using namespace std;
namespace armnn
{
IRuntime* IRuntime::CreateRaw(const CreationOptions& options)
{
return new Runtime(options);
}
IRuntimePtr IRuntime::Create(const CreationOptions& options)
{
return IRuntimePtr(CreateRaw(options), &IRuntime::Destroy);
}
void IRuntime::Destroy(IRuntime* runtime)
{
delete boost::polymorphic_downcast<Runtime*>(runtime);
}
int Runtime::GenerateNetworkId()
{
return m_NetworkIdCounter++;
}
Status Runtime::LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr inNetwork)
{
std::string ignoredErrorMessage;
return LoadNetwork(networkIdOut, std::move(inNetwork), ignoredErrorMessage);
}
Status Runtime::LoadNetwork(NetworkId& networkIdOut,
IOptimizedNetworkPtr inNetwork,
std::string & errorMessage)
{
IOptimizedNetwork* rawNetwork = inNetwork.release();
unique_ptr<LoadedNetwork> loadedNetwork = LoadedNetwork::MakeLoadedNetwork(
std::unique_ptr<OptimizedNetwork>(boost::polymorphic_downcast<OptimizedNetwork*>(rawNetwork)),
errorMessage);
if (!loadedNetwork)
{
return Status::Failure;
}
networkIdOut = GenerateNetworkId();
{
std::lock_guard<std::mutex> lockGuard(m_Mutex);
// Stores the network
m_LoadedNetworks[networkIdOut] = std::move(loadedNetwork);
}
return Status::Success;
}
Status Runtime::UnloadNetwork(NetworkId networkId)
{
#ifdef ARMCOMPUTECL_ENABLED
if (arm_compute::CLScheduler::get().context()() != NULL)
{
// Waits for all queued CL requests to finish before unloading the network they may be using.
try
{
// Coverity fix: arm_compute::CLScheduler::sync() may throw an exception of type cl::Error.
arm_compute::CLScheduler::get().sync();
}
catch (const cl::Error&)
{
BOOST_LOG_TRIVIAL(warning) << "WARNING: Runtime::UnloadNetwork(): an error occurred while waiting for "
"the queued CL requests to finish";
return Status::Failure;
}
}
#endif
{
std::lock_guard<std::mutex> lockGuard(m_Mutex);
if (m_LoadedNetworks.erase(networkId) == 0)
{
BOOST_LOG_TRIVIAL(warning) << "WARNING: Runtime::UnloadNetwork(): " << networkId << " not found!";
return Status::Failure;
}
#ifdef ARMCOMPUTECL_ENABLED
if (arm_compute::CLScheduler::get().context()() != NULL && m_LoadedNetworks.empty())
{
// There are no loaded networks left, so clear the CL cache to free up memory
m_ClContextControl.ClearClCache();
}
#endif
}
BOOST_LOG_TRIVIAL(debug) << "Runtime::UnloadNetwork(): Unloaded network with ID: " << networkId;
return Status::Success;
}
const std::shared_ptr<IProfiler> Runtime::GetProfiler(NetworkId networkId) const
{
auto it = m_LoadedNetworks.find(networkId);
if (it != m_LoadedNetworks.end())
{
auto& loadedNetwork = it->second;
return loadedNetwork->GetProfiler();
}
return nullptr;
}
Runtime::Runtime(const CreationOptions& options)
: m_ClContextControl(options.m_GpuAccTunedParameters.get(),
options.m_EnableGpuProfiling)
, m_NetworkIdCounter(0)
{
BOOST_LOG_TRIVIAL(info) << "ArmNN v" << ARMNN_VERSION << "\n";
m_DeviceSpec.m_SupportedComputeDevices.insert(armnn::Compute::CpuRef);
#if ARMCOMPUTECL_ENABLED
m_DeviceSpec.m_SupportedComputeDevices.insert(armnn::Compute::GpuAcc);
#endif
#if ARMCOMPUTENEON_ENABLED
m_DeviceSpec.m_SupportedComputeDevices.insert(armnn::Compute::CpuAcc);
#endif
}
Runtime::~Runtime()
{
std::vector<int> networkIDs;
try
{
// Coverity fix: The following code may throw an exception of type std::length_error.
std::transform(m_LoadedNetworks.begin(), m_LoadedNetworks.end(),
std::back_inserter(networkIDs),
[](const auto &pair) { return pair.first; });
}
catch (const std::exception& e)
{
// Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
// exception of type std::length_error.
// Using stderr instead in this context as there is no point in nesting try-catch blocks here.
std::cerr << "WARNING: An error has occurred when getting the IDs of the networks to unload: " << e.what()
<< "\nSome of the loaded networks may not be unloaded" << std::endl;
}
// We then proceed to unload all the networks which IDs have been appended to the list
// up to the point the exception was thrown (if any).
for (auto networkID : networkIDs)
{
try
{
// Coverity fix: UnloadNetwork() may throw an exception of type std::length_error,
// boost::log::v2s_mt_posix::odr_violation or boost::log::v2s_mt_posix::system_error
UnloadNetwork(networkID);
}
catch (const std::exception& e)
{
// Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an
// exception of type std::length_error.
// Using stderr instead in this context as there is no point in nesting try-catch blocks here.
std::cerr << "WARNING: An error has occurred when unloading network " << networkID << ": " << e.what()
<< std::endl;
}
}
}
LoadedNetwork* Runtime::GetLoadedNetworkPtr(NetworkId networkId) const
{
std::lock_guard<std::mutex> lockGuard(m_Mutex);
return m_LoadedNetworks.at(networkId).get();
}
TensorInfo Runtime::GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
{
return GetLoadedNetworkPtr(networkId)->GetInputTensorInfo(layerId);
}
TensorInfo Runtime::GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
{
return GetLoadedNetworkPtr(networkId)->GetOutputTensorInfo(layerId);
}
Status Runtime::EnqueueWorkload(NetworkId networkId,
const InputTensors& inputTensors,
const OutputTensors& outputTensors)
{
LoadedNetwork* loadedNetwork = GetLoadedNetworkPtr(networkId);
return loadedNetwork->EnqueueWorkload(inputTensors, outputTensors);
}
}