ArmNN
 23.05
LoadedNetwork Class Reference

#include <LoadedNetwork.hpp>

Public Types

using WorkloadQueue = std::vector< std::unique_ptr< IWorkload > >
 

Public Member Functions

 ~LoadedNetwork ()
 
std::unique_ptr< IWorkingMemHandleCreateWorkingMemHandle (NetworkId networkId)
 Create a new unique WorkingMemHandle object. More...
 
TensorInfo GetInputTensorInfo (LayerBindingId layerId) const
 
TensorInfo GetOutputTensorInfo (LayerBindingId layerId) const
 
std::vector< ImportedInputIdImportInputs (const InputTensors &inputTensors, MemorySource forceImportMemorySource=MemorySource::Undefined)
 
std::vector< ImportedOutputIdImportOutputs (const OutputTensors &outputTensors, MemorySource forceImportMemorySource=MemorySource::Undefined)
 
void ClearImportedInputs (const std::vector< ImportedInputId > inputIds)
 
void ClearImportedOutputs (const std::vector< ImportedOutputId > outputIds)
 
Status EnqueueWorkload (const InputTensors &inputTensors, const OutputTensors &outputTensors, std::vector< ImportedInputId > preImportedInputIds={}, std::vector< ImportedOutputId > preImportedOutputIds={})
 Single thread execution of the loaded network. More...
 
Status Execute (const InputTensors &inputTensors, const OutputTensors &outputTensors, IWorkingMemHandle &workingMemHandle, std::vector< ImportedInputId > preImportedInputs={}, std::vector< ImportedOutputId > preImportedOutputs={})
 Thread safe execution of the loaded network. More...
 
const std::shared_ptr< IProfiler > & GetProfiler () const
 
void FreeWorkingMemory ()
 
void RegisterDebugCallback (const DebugCallbackFunction &func)
 
void SendNetworkStructure (arm::pipe::IProfilingService &profilingService)
 
bool IsAsyncEnabled ()
 
arm::pipe::ProfilingGuid GetNetworkGuid ()
 

Static Public Member Functions

static std::unique_ptr< LoadedNetworkMakeLoadedNetwork (std::unique_ptr< IOptimizedNetwork > net, std::string &errorMessage, const INetworkProperties &networkProperties, arm::pipe::IProfilingService *profilingService)
 

Detailed Description

Definition at line 42 of file LoadedNetwork.hpp.

Member Typedef Documentation

◆ WorkloadQueue

using WorkloadQueue = std::vector<std::unique_ptr<IWorkload> >

Definition at line 45 of file LoadedNetwork.hpp.

Constructor & Destructor Documentation

◆ ~LoadedNetwork()

~LoadedNetwork ( )
inline

Definition at line 47 of file LoadedNetwork.hpp.

48  {
50  }

References LoadedNetwork::FreeWorkingMemory().

Member Function Documentation

◆ ClearImportedInputs()

void ClearImportedInputs ( const std::vector< ImportedInputId inputIds)

Definition at line 1685 of file LoadedNetwork.cpp.

1686 {
1687  for (auto id : inputIds)
1688  {
1689  if (id > m_PreImportedInputHandles.size())
1690  {
1691  throw InvalidArgumentException(fmt::format("ClearImportedInputs::Unknown ImportedInputId: {}", id));
1692  }
1693 
1694  auto& importedTensorHandle = m_PreImportedInputHandles[id].m_TensorHandle;
1695  if (!importedTensorHandle)
1696  {
1697  throw InvalidArgumentException(
1698  fmt::format("ClearImportedInputs::ImportedInput with id: {} has already been deleted", id));
1699  }
1700  // Call Unimport then destroy the tensorHandle
1701  importedTensorHandle->Unimport();
1702  importedTensorHandle = {};
1703  }
1704 }

Referenced by RuntimeImpl::ClearImportedInputs().

◆ ClearImportedOutputs()

void ClearImportedOutputs ( const std::vector< ImportedOutputId outputIds)

Definition at line 1706 of file LoadedNetwork.cpp.

1707 {
1708  for (auto id : outputIds)
1709  {
1710  if (id > m_PreImportedOutputHandles.size())
1711  {
1712  throw InvalidArgumentException(fmt::format("ClearImportedOutputs::Unknown ImportedOutputId: {}", id));
1713  }
1714 
1715  auto& importedTensorHandle = m_PreImportedOutputHandles[id].m_TensorHandle;
1716  if (!importedTensorHandle)
1717  {
1718  throw InvalidArgumentException(
1719  fmt::format("ClearImportedOutputs::ImportedOutput with id: {} has already been deleted", id));
1720  }
1721  // Call Unimport then destroy the tensorHandle
1722  importedTensorHandle->Unimport();
1723  importedTensorHandle = {};
1724  }
1725 }

Referenced by RuntimeImpl::ClearImportedOutputs().

◆ CreateWorkingMemHandle()

std::unique_ptr< IWorkingMemHandle > CreateWorkingMemHandle ( NetworkId  networkId)

Create a new unique WorkingMemHandle object.

Create multiple handles if you wish to have overlapped Execution by calling this function from different threads.

Definition at line 1949 of file LoadedNetwork.cpp.

1950 {
1951  Graph& order = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
1952 
1953  // Tensors that will need to be allocated internally within armnn
1954  std::vector<std::unique_ptr<ITensorHandle>> managedTensorHandles;
1955  // Tensors that will be allocated externally by the user
1956  std::vector<std::unique_ptr<ITensorHandle>> unmanagedTensorHandles;
1957 
1958  std::vector<WorkingMemDescriptor> workingMemDescriptors;
1959  std::vector<std::pair<BackendId, ExecutionData>> executionDataVec;
1960 
1961  auto GetTensorHandle = [&](Layer* layer, const OutputSlot& outputSlot)
1962  {
1963  ITensorHandleFactory::FactoryId factoryId = outputSlot.GetTensorHandleFactoryId();
1964  const TensorInfo& tensorInfo = outputSlot.GetTensorInfo();
1965 
1966  if (factoryId == ITensorHandleFactory::LegacyFactoryId)
1967  {
1968  BackendId id = layer->GetBackendId();
1970  return m_WorkloadFactories.at(id)->CreateTensorHandle(tensorInfo, false);
1972  }
1973  else
1974  {
1975  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1976  ARMNN_ASSERT(handleFactory);
1977  return handleFactory->CreateTensorHandle(tensorInfo, false);
1978  }
1979  };
1980 
1981  struct HandleInfo
1982  {
1983  ITensorHandle* m_TensorHandle;
1984 
1985  bool m_IsInputLayerHandle = false;
1986  bool m_IsOutputLayerHandle = false;
1987 
1988  WorkingMemHandle::InputMemDescriptorCoords m_InputMemDescriptorCoords;
1989  WorkingMemHandle::OutputMemDescriptorCoords m_OutputMemDescriptorCoords;
1990  };
1991 
1992  std::unordered_map<const OutputSlot*, HandleInfo> outputToHandleInfoMap;
1993 
1994  unsigned int layerIndex = 0;
1995  for (auto&& layer : order)
1996  {
1997  // Constant layers execution and management is handled during loaded network construction
1998  if (layer->GetType() == LayerType::Constant)
1999  {
2000  continue;
2001  }
2002 
2003  WorkingMemDescriptor workingMemDescriptor;
2004 
2005  bool isMemoryManaged = true;
2006  bool isInputLayer = false;
2007  bool isOutputLayer = false;
2008  bool isConnectedToOutputLayer = false;
2009 
2010  if (layer->GetType() == LayerType::Input || layer->GetType() == LayerType::MemImport)
2011  {
2012  // Input layers/workloads will not be executed so the descriptor is not added to workingMemDescriptors
2013  // However we will still need to manage the tensorHandle
2014  isInputLayer = true;
2015  isMemoryManaged = !m_NetworkProperties.m_ImportEnabled;
2016  }
2017  else if (layer->GetType() == LayerType::Output)
2018  {
2019  isOutputLayer = true;
2020  }
2021 
2022  unsigned int slotIndex = 0;
2023  // Create a tensor handle for each output slot of a layer
2024  // Once we create it, we start managing its lifetime
2025  for (auto& slot : layer->GetOutputSlots())
2026  {
2027  for (unsigned int i = 0; i < slot.GetNumConnections(); ++i)
2028  {
2029  if ((slot.GetConnection(i)->GetOwningLayer().GetType() == LayerType::Output))
2030  {
2031  if (!isConnectedToOutputLayer)
2032  {
2033  isConnectedToOutputLayer = true;
2034  // If Export is enabled disable memory management, so we can export, otherwise we do a copy
2035  isMemoryManaged = !m_NetworkProperties.m_ExportEnabled;
2036  }
2037  else
2038  {
2039  // Importing in this case would likely cause unexpected behaviour, so we disallow it.
2040  ARMNN_LOG(warning) <<
2041  fmt::format("Layer name: '{0}' guid: '{1}' has two or more OutputLayers connected to it. "
2042  "This will prevent importing on the connected OutputLayers.",
2043  layer->GetName(), layer->GetGuid());
2044  isMemoryManaged = true;
2045  }
2046  }
2047  }
2048 
2049  ITensorHandle* tensorHandle;
2050  if (isMemoryManaged)
2051  {
2052  managedTensorHandles.emplace_back(GetTensorHandle(layer, slot));
2053  tensorHandle = managedTensorHandles.back().get();
2054  }
2055  else
2056  {
2057  unmanagedTensorHandles.emplace_back(GetTensorHandle(layer, slot));
2058  tensorHandle = unmanagedTensorHandles.back().get();
2059  }
2060 
2061  workingMemDescriptor.m_Outputs.push_back(tensorHandle);
2062 
2063  HandleInfo& handleInfo = outputToHandleInfoMap[&slot];
2064  handleInfo.m_TensorHandle = tensorHandle;
2065 
2066  // Store the coordinates of the current layer's OutputSlot that is connected to the OutputLayer
2067  if (isConnectedToOutputLayer)
2068  {
2069  handleInfo.m_IsOutputLayerHandle = true;
2070  handleInfo.m_OutputMemDescriptorCoords.m_OutputSlotCoords = {layerIndex, slotIndex};
2071  }
2072  // Store the LayerBindingId of the InputLayer
2073  if (isInputLayer)
2074  {
2075  handleInfo.m_IsInputLayerHandle = true;
2076  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
2077  handleInfo.m_InputMemDescriptorCoords.m_LayerBindingId = bindingId;
2078  }
2079  slotIndex++;
2080  }
2081  // Loop through the input slots in the same layer and decrement the reference counter associated
2082  // to each tensor handle we encounter.
2083  // Once it reaches zero, the lifetime of the tensor handle has ended, and we mark its memory as available
2084  // so that the next tensor handle with a non overlapping lifetime can share its memory.
2085  for (auto& slot : layer->GetInputSlots())
2086  {
2087  ARMNN_ASSERT(slot.GetConnection());
2088  auto outputSlot = slot.GetConnectedOutputSlot();
2089  auto key = outputSlot->GetOwningLayer().GetGuid();
2090 
2091  // Constant layers execution and management is handled during loaded network construction
2092  auto found = m_ConstantTensorHandles.find(key);
2093  if (found != m_ConstantTensorHandles.end())
2094  {
2095  ITensorHandle* tensorHandle = found->second;
2096  workingMemDescriptor.m_Inputs.push_back(tensorHandle);
2097 
2098  // Odd case where a constant layer is connected to an output layer
2099  // We will need to create a HandleInfo to track it
2100  if (isOutputLayer)
2101  {
2102  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
2103 
2104  HandleInfo& handleInfo = outputToHandleInfoMap[outputSlot];
2105  handleInfo.m_TensorHandle = tensorHandle;
2106  handleInfo.m_IsOutputLayerHandle = true;
2107  handleInfo.m_OutputMemDescriptorCoords.m_LayerBindingIds.push_back(bindingId);
2108  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, 0});
2109  }
2110  continue;
2111  }
2112 
2113  HandleInfo& handleInfo = outputToHandleInfoMap.at(outputSlot);
2114 
2115  ITensorHandle* inputTensorHandle = handleInfo.m_TensorHandle;
2116  workingMemDescriptor.m_Inputs.push_back(inputTensorHandle);
2117 
2118  // Store the LayerBindingId of the OutputLayer
2119  if (isOutputLayer)
2120  {
2121  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
2122  handleInfo.m_OutputMemDescriptorCoords.m_LayerBindingIds.push_back(bindingId);
2123  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, 0});
2124  }
2125  // In this case the layer is not an Output Layer but shares its input tensorhandle with an OutputLayer
2126  // It will need to be updated as well, if we swap out the tensorhandle
2127  else if (handleInfo.m_IsOutputLayerHandle)
2128  {
2129  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, slot.GetSlotIndex()});
2130  }
2131 
2132  // Store the coordinates of the InputSlots connected to the InputLayer
2133  // There can be more than one InputSlot connected to an InputLayer, so we use a vector
2134  if (handleInfo.m_IsInputLayerHandle)
2135  {
2136  std::pair<LayerGuid, unsigned int> connectionLocation{layerIndex, slot.GetSlotIndex()};
2137  handleInfo.m_InputMemDescriptorCoords.m_InputSlotCoords.emplace_back(connectionLocation);
2138  }
2139  }
2140 
2141  // Input/Output layers/workloads will not be executed, so the descriptor is not added to workingMemDescriptors
2142  // However we will still need to manage the tensorHandle
2143  if (!isInputLayer)
2144  {
2145  // Simply auto initialise ExecutionData here, so it's added only for the layer that require execution.
2146  // The memory and data will be allocated/assigned for the void* in WorkingMemHandle::Allocate.
2147  std::pair<BackendId, ExecutionData> dataPair;
2148  dataPair.first = layer->GetBackendId();
2149 
2150  executionDataVec.push_back(dataPair);
2151  workingMemDescriptors.push_back(workingMemDescriptor);
2152 
2153  layerIndex++;
2154  }
2155  }
2156 
2157  std::vector<std::pair<std::shared_ptr<TensorMemory>, MemorySource>> tensorMemory;
2158 
2159  auto externalMemoryManager = CreateExternalMemoryManger(tensorMemory);
2160 
2161  // Sort m_TensorMemory, so it's order matches the outputSlot order
2162  std::sort(tensorMemory.begin(), tensorMemory.end(),
2163  [](const std::pair<std::shared_ptr<TensorMemory>, MemorySource>& lhs,
2164  const std::pair<std::shared_ptr<TensorMemory>, MemorySource>& rhs)
2165  {
2166  return lhs.first->m_OutputSlotId < rhs.first->m_OutputSlotId;
2167  });
2168 
2169  std::vector<WorkingMemHandle::InputMemDescriptorCoords> inputConnectionsInfo;
2170  std::vector<WorkingMemHandle::OutputMemDescriptorCoords> outputConnectionsInfo;
2171 
2172  for (const auto& handleInfo: outputToHandleInfoMap)
2173  {
2174  if (handleInfo.second.m_IsOutputLayerHandle)
2175  {
2176  outputConnectionsInfo.emplace_back(handleInfo.second.m_OutputMemDescriptorCoords);
2177  }
2178 
2179  if (handleInfo.second.m_IsInputLayerHandle)
2180  {
2181  inputConnectionsInfo.emplace_back(handleInfo.second.m_InputMemDescriptorCoords);
2182  }
2183  }
2184 
2185  return std::make_unique<WorkingMemHandle>(networkId,
2186  inputConnectionsInfo,
2187  outputConnectionsInfo,
2188  workingMemDescriptors,
2189  std::move(externalMemoryManager),
2190  std::move(tensorMemory),
2191  std::move(managedTensorHandles),
2192  std::move(unmanagedTensorHandles),
2193  executionDataVec,
2194  &m_Backends);
2195 }

References ARMNN_ASSERT, ARMNN_NO_DEPRECATE_WARN_BEGIN, ARMNN_NO_DEPRECATE_WARN_END, ITensorHandleFactory::CreateTensorHandle(), Layer::GetBackendId(), TensorHandleFactoryRegistry::GetFactory(), and ITensorHandleFactory::LegacyFactoryId.

Referenced by RuntimeImpl::CreateWorkingMemHandle().

◆ EnqueueWorkload()

Status EnqueueWorkload ( const InputTensors inputTensors,
const OutputTensors outputTensors,
std::vector< ImportedInputId preImportedInputIds = {},
std::vector< ImportedOutputId preImportedOutputIds = {} 
)

Single thread execution of the loaded network.

Definition at line 839 of file LoadedNetwork.cpp.

843 {
844  const Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
845 
846  // Walk graph to determine the order of execution.
847  if (graph.GetNumLayers() < 2)
848  {
849  ARMNN_LOG(warning) << "IRuntime::EnqueueWorkload()::Less than two nodes in graph";
850  return Status::Failure;
851  }
852 
853  // Data that must be kept alive for the entire execution of the workload.
854  WorkloadData workloadData(inputTensors, outputTensors);
855 
856  // Input tensors can be provided as parameters or pre imported. Either way the number of
857  // tensors should match the number of inputs.
858  if (graph.GetNumInputs() != (inputTensors.size() + preImportedInputIds.size()))
859  {
860  throw InvalidArgumentException("Number of inputs provided does not match network.");
861  }
862 
863  // For each input to the network, call EnqueueInput with the data passed by the user.
864  {
866  m_InputQueue.clear();
867  m_InputQueue.reserve(graph.GetNumInputs());
868 
869  unsigned int inputIndex = 0;
870  unsigned int importedInputIdIndex = 0;
871  std::sort(preImportedInputIds.begin(), preImportedInputIds.end());
872  for (const BindableLayer* inputLayer : graph.GetInputLayers())
873  {
874  if (importedInputIdIndex < preImportedInputIds.size() &&
875  inputIndex == preImportedInputIds[importedInputIdIndex])
876  {
877  // Only replace tensorhandles if they have not already been replaced
878  if (!m_IsInputImported[inputIndex])
879  {
880  auto outputTensorHandle = m_PreImportedInputHandles[inputIndex].m_TensorHandle.get();
881 
882  for (const auto& workloadInfo: m_InputWorkloadSlotPairs[inputLayer->GetBindingId()])
883  {
884  auto workload = m_WorkloadQueue[workloadInfo.m_WorkloadIndex].get();
885  workload->ReplaceInputTensorHandle(outputTensorHandle, workloadInfo.m_SlotIndex);
886  }
887  m_IsInputImported[inputIndex] = true;
888  }
889  importedInputIdIndex++;
890  }
891  else
892  {
893  if (m_IsInputImported[inputIndex])
894  {
895  OutputHandler& handler = const_cast<OutputHandler&>(inputLayer->GetOutputHandler(0));
896 
897  for (const auto& workloadInfo: m_InputWorkloadSlotPairs[inputLayer->GetBindingId()])
898  {
899  auto workload = m_WorkloadQueue[workloadInfo.m_WorkloadIndex].get();
900  workload->ReplaceInputTensorHandle(handler.GetData(), workloadInfo.m_SlotIndex);
901  }
902 
903  m_IsInputImported[inputIndex] = false;
904  }
905 
906  // InputTensorHandle is not imported yet, process to enqueue input
907  const TensorPin& pin = workloadData.GetInputTensorPin(inputLayer->GetBindingId());
908  EnqueueInput(*inputLayer, pin.GetTensorHandle(), pin.GetTensorInfo());
909  }
910  inputIndex++;
911  }
912  }
913  // For each output to the network, call EnqueueOutput with the data passed by the user.
914  {
916  m_OutputQueue.clear();
917  m_OutputQueue.reserve(graph.GetNumOutputs());
918 
919  if (preImportedOutputIds.size() > graph.GetNumOutputs())
920  {
921  throw InvalidArgumentException("Invalid number of preImportedOutputIds");
922  }
923 
924  unsigned int outputIndex = 0;
925  unsigned int importedOutputIdIndex = 0;
926  std::sort(preImportedOutputIds.begin(), preImportedOutputIds.end());
927  for (const BindableLayer* outputLayer : graph.GetOutputLayers())
928  {
929  if (importedOutputIdIndex < preImportedOutputIds.size() &&
930  outputIndex == preImportedOutputIds[importedOutputIdIndex])
931  {
932  // Only replace tensorhandles if they have not already been replaced
933  ITensorHandle* inputTensorHandle = m_PreImportedOutputHandles[outputIndex].m_TensorHandle.get();
934 
935  if (!m_IsOutputImported[outputIndex])
936  {
937  const auto bindingId = outputLayer->GetBindingId();
938  const auto& indices = m_OutputWorkloadSlotPairs[bindingId];
939 
940  auto outputWorkload = m_WorkloadQueue[indices.m_OutputSlotIndices.m_WorkloadIndex].get();
941 
942  outputWorkload->ReplaceOutputTensorHandle(inputTensorHandle,
943  indices.m_OutputSlotIndices.m_SlotIndex);
944 
945  for (const auto& workloadInfo: indices.m_InputSlotIndices)
946  {
947  auto inputWorkload = m_WorkloadQueue[workloadInfo.m_WorkloadIndex].get();
948  inputWorkload->ReplaceInputTensorHandle(inputTensorHandle, workloadInfo.m_SlotIndex);
949  }
950  m_IsOutputImported[outputIndex] = true;
951  }
952 
953  ARMNN_ASSERT_MSG(inputTensorHandle != nullptr, "Data should have been allocated.");
954  MemSyncQueueDescriptor syncDesc;
955  syncDesc.m_Inputs.push_back(inputTensorHandle);
956  WorkloadInfo info;
957  info.m_InputTensorInfos.push_back(
958  outputLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo());
959  auto syncWorkload = std::make_unique<SyncMemGenericWorkload>(syncDesc, info);
960  ARMNN_ASSERT_MSG(syncWorkload, "No sync workload created");
961  m_OutputQueue.push_back(move(syncWorkload));
962  importedOutputIdIndex++;
963  }
964  else
965  {
966  if (m_IsOutputImported[outputIndex])
967  {
968  const auto bindingId = outputLayer->GetBindingId();
969  const auto& indices = m_OutputWorkloadSlotPairs[bindingId];
970 
971  auto outputWorkload = m_WorkloadQueue[indices.m_OutputSlotIndices.m_WorkloadIndex].get();
972  const OutputHandler& outputHandler =
973  outputLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetOutputHandler();
974 
975  outputWorkload->ReplaceOutputTensorHandle(
976  outputHandler.GetData(), indices.m_OutputSlotIndices.m_SlotIndex);
977 
978  for (const auto& workloadInfo: indices.m_InputSlotIndices)
979  {
980  auto inputWorkload = m_WorkloadQueue[workloadInfo.m_WorkloadIndex].get();
981  inputWorkload->ReplaceInputTensorHandle(outputHandler.GetData(), workloadInfo.m_SlotIndex);
982  }
983  m_IsOutputImported[outputIndex] = false;
984  }
985 
986  const TensorPin& pin = workloadData.GetOutputTensorPin(outputLayer->GetBindingId());
987  // OutputTensorHandle is not imported yet, process to enqueue Output
988  EnqueueOutput(*outputLayer, pin.GetTensorHandle(), pin.GetTensorInfo());
989  }
990  outputIndex++;
991  }
992  }
993 
994  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
995  TimelineUtilityMethods::GetTimelineUtils(*m_ProfilingService);
996  ProfilingGuid inferenceGuid = m_ProfilingService->GetNextGuid();
997  if (timelineUtils)
998  {
999  // Add inference timeline trace if profiling is enabled.
1000  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
1001  timelineUtils->CreateTypedEntity(inferenceGuid, LabelsAndEventClasses::INFERENCE_GUID);
1002  timelineUtils->CreateRelationship(ProfilingRelationshipType::RetentionLink,
1003  networkGuid,
1004  inferenceGuid,
1005  LabelsAndEventClasses::EXECUTION_OF_GUID);
1006  timelineUtils->RecordEvent(inferenceGuid, LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
1007  }
1008 
1009  bool executionSucceeded = true;
1010 
1011  {
1012  if (m_ProfilingService->IsProfilingEnabled())
1013  {
1014  m_ProfilingService->IncrementCounterValue(INFERENCES_RUN);
1015  }
1017  ARMNN_SCOPED_HEAP_PROFILING("Executing");
1018  executionSucceeded = Execute(timelineUtils, inferenceGuid);
1019  }
1020 
1021  if (timelineUtils)
1022  {
1023  // Add end of life of the inference timeline if profiling is enabled.
1024  timelineUtils->RecordEvent(inferenceGuid, LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
1025  timelineUtils->Commit();
1026  }
1027 
1028  return executionSucceeded ? Status::Success : Status::Failure;
1029 }

References ARMNN_ASSERT_MSG, ARMNN_LOG, ARMNN_SCOPED_PROFILING_EVENT, armnn::Failure, OutputHandler::GetData(), Graph::GetInputLayers(), Graph::GetNumInputs(), Graph::GetNumLayers(), Graph::GetNumOutputs(), Graph::GetOutputLayers(), armnn::info, QueueDescriptor::m_Inputs, armnn::Undefined, and armnn::warning.

Referenced by RuntimeImpl::EnqueueWorkload().

◆ Execute()

Status Execute ( const InputTensors inputTensors,
const OutputTensors outputTensors,
IWorkingMemHandle workingMemHandle,
std::vector< ImportedInputId preImportedInputs = {},
std::vector< ImportedOutputId preImportedOutputs = {} 
)

Thread safe execution of the loaded network.

Definition at line 1727 of file LoadedNetwork.cpp.

1732 {
1733  const Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
1734 
1735  if (inputTensors.size() + preImportedInputs.size() != graph.GetNumInputs())
1736  {
1737  if (preImportedInputs.empty())
1738  {
1739  throw InvalidArgumentException("LoadedNetwork::Execute: Number of inputs provided does not match network.");
1740  }
1741  else
1742  {
1743  throw InvalidArgumentException("LoadedNetwork::Execute: "
1744  "Number of inputs + preImportedInputs provided does not match network.");
1745  }
1746  }
1747 
1748  if (outputTensors.size() + preImportedOutputs.size() != graph.GetNumOutputs())
1749  {
1750  if (preImportedOutputs.empty())
1751  {
1752  throw InvalidArgumentException("LoadedNetwork::Execute: "
1753  "Number of outputs provided does not match network.");
1754  }
1755  else
1756  {
1757  throw InvalidArgumentException("LoadedNetwork::Execute: "
1758  "Number of outputs + preImportedOutputs provided does not match network.");
1759  }
1760  }
1761 
1762  WorkingMemHandle& workingMemHandle = dynamic_cast<WorkingMemHandle&>(iWorkingMemHandle);
1763  // Collect all the given LayerBindingIds and check them for duplicates and unknowns.
1764  std::vector<LayerBindingId>& bindingIds = workingMemHandle.GetBindingIdVector();
1765  unsigned int index = 0;
1766  for (auto pair : inputTensors)
1767  {
1768  bindingIds[index++] = pair.first;
1769  }
1770  for (ImportedInputId id : preImportedInputs)
1771  {
1772  bindingIds[index++] = ValidateImportedInputID(id);
1773  }
1774  for (auto pair : outputTensors)
1775  {
1776  bindingIds[index++] = pair.first;
1777  }
1778  for (ImportedOutputId id : preImportedOutputs)
1779  {
1780  bindingIds[index++] = ValidateImportedOutputID(id);
1781  }
1782 
1783  workingMemHandle.ValidateBindingIds();
1784 
1785  auto resetMemHandle = [&]()
1786  {
1787  for (ImportedInputId id: preImportedInputs)
1788  {
1789  const LayerBindingId layerBindingId = m_PreImportedInputHandles[id].m_LayerBindingId;
1790 
1791  auto inputHandle = workingMemHandle.GetInputHandle(layerBindingId);
1792  auto inputConnections = workingMemHandle.GetInputConnections(layerBindingId);
1793  for (auto it : inputConnections)
1794  {
1795  *it = inputHandle;
1796  }
1797  }
1798 
1799  for (ImportedOutputId id: preImportedOutputs)
1800  {
1801  const LayerBindingId layerBindingId = m_PreImportedOutputHandles[id].m_LayerBindingId;
1802 
1803  auto outputHandle = workingMemHandle.GetOutputHandle(layerBindingId);
1804  auto outputConnections = workingMemHandle.GetOutputConnection(layerBindingId);
1805 
1806  for (auto it : outputConnections)
1807  {
1808  *it = outputHandle;
1809  }
1810  }
1811  };
1812 
1813  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
1814  TimelineUtilityMethods::GetTimelineUtils(*m_ProfilingService);
1815  ProfilingGuid inferenceGuid = m_ProfilingService->GetNextGuid();
1816  if (timelineUtils)
1817  {
1818  // Add inference timeline trace if profiling is enabled.
1819  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
1820  timelineUtils->CreateTypedEntity(inferenceGuid,LabelsAndEventClasses::INFERENCE_GUID);
1821  timelineUtils->CreateRelationship(ProfilingRelationshipType::RetentionLink,
1822  networkGuid,
1823  inferenceGuid,
1824  LabelsAndEventClasses::EXECUTION_OF_GUID);
1825  timelineUtils->RecordEvent(inferenceGuid,LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
1826  }
1827 
1828  bool executionSucceeded = true;
1829 
1830  if (timelineUtils)
1831  {
1832  // Add end of life of the inference timeline if profiling is enabled.
1833  timelineUtils->RecordEvent(inferenceGuid,LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
1834  timelineUtils->Commit();
1835  }
1836 
1837  if (!workingMemHandle.IsAllocated())
1838  {
1839  workingMemHandle.Allocate();
1840  }
1841 
1842  {
1844  for (auto pair : inputTensors)
1845  {
1846  EnqueueInput(pair.second, workingMemHandle.GetInputHandle(pair.first));
1847  }
1848 
1849  // Swap in the pre-imported inputs if any
1850  for (ImportedInputId id : preImportedInputs)
1851  {
1852  const ImportedTensorHandlePin& importedInputPin = m_PreImportedInputHandles[id];
1853  const LayerBindingId layerBindingId = m_PreImportedInputHandles[id].m_LayerBindingId;
1854  const auto& preimportedHandle = importedInputPin.m_TensorHandle;
1855 
1856  auto inputConnections = workingMemHandle.GetInputConnections(layerBindingId);
1857  for (auto it : inputConnections)
1858  {
1859  *it = preimportedHandle.get();
1860  }
1861  }
1862  }
1863  {
1865  if (m_NetworkProperties.m_ExportEnabled)
1866  {
1867  for (auto pair: outputTensors)
1868  {
1869  ImportOutputTensor(pair.second, workingMemHandle.GetOutputHandle(pair.first));
1870  }
1871  }
1872 
1873  for (ImportedOutputId id : preImportedOutputs)
1874  {
1875  const ImportedTensorHandlePin& importedOutputPin = m_PreImportedOutputHandles[id];
1876  const LayerBindingId layerBindingId = m_PreImportedOutputHandles[id].m_LayerBindingId;
1877  const auto& preimportedHandle = importedOutputPin.m_TensorHandle;
1878 
1879  auto outputConnections = workingMemHandle.GetOutputConnection(layerBindingId);
1880  for (auto it : outputConnections)
1881  {
1882  *it = preimportedHandle.get();
1883  }
1884  }
1885  }
1886 
1887  auto Fail = [&](const std::exception& error)
1888  {
1889  ARMNN_LOG(error) << "An error occurred attempting to execute a workload: " << error.what();
1890  executionSucceeded = false;
1891  };
1892  ProfilingDynamicGuid workloadInferenceID(0);
1893 
1894  try
1895  {
1896  for (unsigned int i = 0; i < m_WorkloadQueue.size(); ++i)
1897  {
1898  auto& workload = m_WorkloadQueue[i];
1899  if (timelineUtils)
1900  {
1901  workloadInferenceID = timelineUtils->RecordWorkloadInferenceAndStartOfLifeEvent(workload->GetGuid(),
1902  inferenceGuid);
1903  }
1904 
1905  workload->ExecuteAsync(workingMemHandle.GetExecutionDataAt(i).second);
1906 
1907  if (timelineUtils)
1908  {
1909  timelineUtils->RecordEndOfLifeEvent(workloadInferenceID);
1910  }
1911  }
1912  }
1913  catch (const RuntimeException& error)
1914  {
1915  resetMemHandle();
1916  Fail(error);
1917  }
1918  catch (const std::runtime_error& error)
1919  {
1920  resetMemHandle();
1921  Fail(error);
1922  }
1923  catch (...)
1924  {
1925  resetMemHandle();
1926  throw;
1927  }
1928 
1929  if (!m_NetworkProperties.m_ExportEnabled)
1930  {
1931  for (auto pair: outputTensors)
1932  {
1933  CopyToOutputTensor(pair.second, workingMemHandle.GetOutputHandle(pair.first));
1934  }
1935  }
1936  else
1937  {
1938  ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "SyncMemGeneric_Execute");
1939  workingMemHandle.MemSyncOutputs();
1940  }
1941 
1942  resetMemHandle();
1943 
1944  return executionSucceeded ? Status::Success : Status::Failure;
1945 }

References WorkingMemHandle::Allocate(), ARMNN_LOG, ARMNN_SCOPED_PROFILING_EVENT, armnn::CopyToOutputTensor(), armnn::error, armnn::Failure, WorkingMemHandle::GetBindingIdVector(), WorkingMemHandle::GetExecutionDataAt(), WorkingMemHandle::GetInputConnections(), WorkingMemHandle::GetInputHandle(), Graph::GetNumInputs(), Graph::GetNumOutputs(), WorkingMemHandle::GetOutputConnection(), WorkingMemHandle::GetOutputHandle(), WorkingMemHandle::IsAllocated(), INetworkProperties::m_ExportEnabled, WorkingMemHandle::MemSyncOutputs(), armnn::Success, armnn::Undefined, and WorkingMemHandle::ValidateBindingIds().

Referenced by RuntimeImpl::Execute().

◆ FreeWorkingMemory()

void FreeWorkingMemory ( )

Definition at line 1222 of file LoadedNetwork.cpp.

1223 {
1224 #if !defined(ARMNN_DISABLE_THREADS)
1225  std::lock_guard<std::mutex> lockGuard(m_WorkingMemMutex);
1226 #endif
1227 
1228  if (!m_IsWorkingMemAllocated)
1229  {
1230  return;
1231  }
1232 
1233  if (m_ExternalMemoryManager)
1234  {
1235  m_ExternalMemoryManager->Deallocate();
1236  }
1237 
1238  // Informs the memory managers to release memory in its respective memory group
1239  for (auto&& memoryManager : m_BackendMemoryMangers)
1240  {
1241  if (memoryManager)
1242  {
1243  memoryManager->Release();
1244  }
1245  }
1246  m_TensorHandleFactoryRegistry.ReleaseMemory();
1247  m_IsWorkingMemAllocated = false;
1248 }

References TensorHandleFactoryRegistry::ReleaseMemory().

Referenced by RuntimeImpl::CreateWorkingMemHandle(), RuntimeImpl::EnqueueWorkload(), and LoadedNetwork::~LoadedNetwork().

◆ GetInputTensorInfo()

TensorInfo GetInputTensorInfo ( LayerBindingId  layerId) const

Definition at line 697 of file LoadedNetwork.cpp.

698 {
699  for (auto&& inputLayer : m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetInputLayers())
700  {
701  ARMNN_ASSERT_MSG(inputLayer->GetNumOutputSlots() == 1, "Input layer should have exactly 1 output slot");
702  if (inputLayer->GetBindingId() == layerId)
703  {
704  return inputLayer->GetOutputSlot(0).GetTensorInfo();
705  }
706  }
707 
708  throw InvalidArgumentException(fmt::format("No input layer is associated with id {}", layerId));
709 }

References ARMNN_ASSERT_MSG.

Referenced by RuntimeImpl::GetInputTensorInfo().

◆ GetNetworkGuid()

ProfilingGuid GetNetworkGuid ( )

Definition at line 692 of file LoadedNetwork.cpp.

693 {
694  return m_OptimizedNetwork->GetGuid();
695 }

◆ GetOutputTensorInfo()

TensorInfo GetOutputTensorInfo ( LayerBindingId  layerId) const

Definition at line 711 of file LoadedNetwork.cpp.

712 {
713  for (auto&& outputLayer : m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetOutputLayers())
714  {
715  ARMNN_ASSERT_MSG(outputLayer->GetNumInputSlots() == 1, "Output layer should have exactly 1 input slot");
716  ARMNN_ASSERT_MSG(outputLayer->GetInputSlot(0).GetConnection(), "Input slot on Output layer must be connected");
717  if (outputLayer->GetBindingId() == layerId)
718  {
719  return outputLayer->GetInputSlot(0).GetConnection()->GetTensorInfo();
720  }
721  }
722 
723  throw InvalidArgumentException(fmt::format("No output layer is associated with id {}", layerId));
724 }

References ARMNN_ASSERT_MSG.

Referenced by RuntimeImpl::GetOutputTensorInfo().

◆ GetProfiler()

const std::shared_ptr<IProfiler>& GetProfiler ( ) const
inline

Definition at line 87 of file LoadedNetwork.hpp.

87 { return m_OptimizedNetwork->GetProfiler(); }

Referenced by RuntimeImpl::CreateWorkingMemHandle(), RuntimeImpl::EnqueueWorkload(), and RuntimeImpl::Execute().

◆ ImportInputs()

std::vector< ImportedInputId > ImportInputs ( const InputTensors inputTensors,
MemorySource  forceImportMemorySource = MemorySource::Undefined 
)

Definition at line 1418 of file LoadedNetwork.cpp.

1420 {
1421  if (!m_NetworkProperties.m_AsyncEnabled)
1422  {
1423  // Cannot import if import is not enabled and forceImportMemorySource is undefined
1424  if (forceImportMemorySource == MemorySource::Undefined)
1425  {
1426  throw MemoryImportException("ImportInputs: Memory Import failed, NetworkProperties.m_ImportEnabled");
1427  }
1428  // The number of pre imported tensors should not exceed the number of inputs.
1429  if (inputTensors.size() > m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetNumInputs())
1430  {
1431  throw MemoryImportException("ImportInputs: The number of tensors provided exceeds the number of inputs.");
1432  }
1433 
1434  std::vector<ImportedInputId> importedInputs;
1435  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1436  unsigned int inputIndex = 0;
1437  for (const BindableLayer* inputLayer : graph.GetInputLayers())
1438  {
1439  auto outputTensorHandle = m_PreImportedInputHandles[inputIndex].m_TensorHandle.get();
1440 
1441  if (!outputTensorHandle)
1442  {
1443  inputIndex++;
1444  continue;
1445  }
1446 
1447  auto layerBindingId = inputLayer->GetBindingId();
1448  auto it = std::find_if(inputTensors.begin(), inputTensors.end(), [=](const auto& inputTensor)
1449  {
1450  return inputTensor.first == layerBindingId;
1451  });
1452 
1453  if (it == inputTensors.end())
1454  {
1455  inputIndex++;
1456  continue;
1457  }
1458 
1459  const auto& inputTensor = *it;
1460  std::unique_ptr<ITensorHandle> passThroughTensorHandle =
1461  std::make_unique<ConstPassthroughTensorHandle>(inputTensor.second.GetInfo(),
1462  inputTensor.second.GetMemoryArea());
1463 
1464  try
1465  {
1466  if (outputTensorHandle->CanBeImported(passThroughTensorHandle->Map(), forceImportMemorySource)
1467  && (outputTensorHandle->Import(passThroughTensorHandle->Map(), forceImportMemorySource)))
1468  {
1469  importedInputs.push_back(inputIndex);
1470  }
1471  passThroughTensorHandle->Unmap();
1472  }
1473  catch(const MemoryImportException& exception)
1474  {
1475  ARMNN_LOG(error) << "An error occurred attempting to import input_"
1476  << inputIndex << " : " << exception.what();
1477  passThroughTensorHandle->Unmap();
1478  }
1479  inputIndex++;
1480  }
1481 
1482  return importedInputs;
1483  }
1484  else
1485  {
1486  // Import when the import of network properties is enabled
1487  std::vector<ImportedInputId> importedInputs;
1488  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1489 
1490  for (auto inputTensor : inputTensors)
1491  {
1492  auto layerBindingId = inputTensor.first;
1493  auto it = std::find_if(graph.GetInputLayers().begin(), graph.GetInputLayers().end(), [=](auto* layer)
1494  {
1495  return layer->GetBindingId() == layerBindingId;
1496  });
1497 
1498  if (it == graph.GetInputLayers().end())
1499  {
1500  throw MemoryImportException(fmt::format(
1501  "ImportInputs: Memory Import failed, unknown LayerBindingId: {}", layerBindingId));
1502  }
1503 
1504  const Layer* layer = *it;
1505  if (layer->GetType() != LayerType::Input)
1506  {
1507  throw InvalidArgumentException("ImportInputs: given layer not an InputLayer");
1508  }
1509 
1510  auto& backend = m_Backends.at(layer->GetBackendId());
1511  if (!HasCapability(BackendOptions::BackendOption{"PreImportIOTensors", true}, backend->GetCapabilities()))
1512  {
1513  std::string er = backend->GetId();
1514  er += " does not have PreImportIOTensors capability";
1515  throw BackendCapabilityException(er);
1516  }
1517 
1518  const OutputSlot& outputSlot = layer->GetOutputSlots()[0];
1519 
1520  ITensorHandleFactory::FactoryId factoryId = outputSlot.GetTensorHandleFactoryId();
1521  const TensorInfo& tensorInfo = outputSlot.GetTensorInfo();
1522 
1523  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1524  ARMNN_ASSERT(handleFactory);
1525 
1526  ImportedTensorHandlePin importedTensorHandlePin{layerBindingId,
1527  handleFactory->CreateTensorHandle(tensorInfo, false)};
1528 
1529  ITensorHandle* tensorHandle = importedTensorHandlePin.m_TensorHandle.get();
1530 
1531  if (!CheckFlag(tensorHandle->GetImportFlags(), forceImportMemorySource))
1532  {
1533  throw MemoryImportException(
1534  fmt::format("ImportInputs: Memory Import failed, backend: "
1535  "{} does not support importing from source {}"
1536  , factoryId, m_NetworkProperties.m_InputSource));
1537  }
1538 
1539  std::unique_ptr<ITensorHandle> passThroughTensorHandle =
1540  std::make_unique<ConstPassthroughTensorHandle>(inputTensor.second.GetInfo(),
1541  inputTensor.second.GetMemoryArea());
1542 
1543  if (tensorHandle->Import(passThroughTensorHandle->Map(), forceImportMemorySource))
1544  {
1545  importedInputs.push_back(m_CurImportedInputId++);
1546  passThroughTensorHandle->Unmap();
1547  }
1548  else
1549  {
1550  passThroughTensorHandle->Unmap();
1551  throw MemoryImportException("ImportInputs: Memory Import failed");
1552  }
1553 
1554  m_PreImportedInputHandles.push_back(std::move(importedTensorHandlePin));
1555  }
1556  return importedInputs;
1557  }
1558 }

References ARMNN_ASSERT, ARMNN_LOG, Graph::InputLayersAccessor::begin(), armnn::CheckFlag(), ITensorHandleFactory::CreateTensorHandle(), Graph::InputLayersAccessor::end(), armnn::error, Layer::GetBackendId(), TensorHandleFactoryRegistry::GetFactory(), ITensorHandle::GetImportFlags(), Graph::GetInputLayers(), Layer::GetOutputSlots(), OutputSlot::GetTensorHandleFactoryId(), OutputSlot::GetTensorInfo(), Layer::GetType(), armnn::HasCapability(), ITensorHandle::Import(), armnn::Input, INetworkProperties::m_AsyncEnabled, INetworkProperties::m_InputSource, armnn::Undefined, and Exception::what().

Referenced by RuntimeImpl::ImportInputs().

◆ ImportOutputs()

std::vector< ImportedOutputId > ImportOutputs ( const OutputTensors outputTensors,
MemorySource  forceImportMemorySource = MemorySource::Undefined 
)

Definition at line 1560 of file LoadedNetwork.cpp.

1562 {
1563  if (!m_NetworkProperties.m_AsyncEnabled)
1564  {
1565  // Cannot import if import is not enabled and forceImportMemorySource is undefined
1566  if (forceImportMemorySource == MemorySource::Undefined)
1567  {
1568  throw MemoryImportException("ImportOutputs: Memory Import failed, NetworkProperties.m_ImportEnabled");
1569  }
1570  // If forceImportMemorySource is defined, try import if memory is aligned
1571  if (outputTensors.size() != m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetNumOutputs())
1572  {
1573  throw MemoryImportException("ImportOutputs: Force Import failed, incorrect number of tensors");
1574  }
1575  std::vector<ImportedOutputId> importedOutputs;
1576  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1577 
1578  unsigned int outputIndex = 0;
1579  for (const BindableLayer* const outputLayer : graph.GetOutputLayers())
1580  {
1581  auto inputTensorHandle = m_PreImportedOutputHandles[outputIndex].m_TensorHandle.get();
1582  if (!inputTensorHandle)
1583  {
1584  outputIndex++;
1585  continue;
1586  }
1587 
1588  auto layerBindingId = outputLayer->GetBindingId();
1589  auto it = std::find_if(outputTensors.begin(), outputTensors.end(), [=] (const auto& outputTensor)
1590  {
1591  return outputTensor.first == layerBindingId;
1592  });
1593 
1594  if (it == outputTensors.end())
1595  {
1596  outputIndex++;
1597  continue;
1598  }
1599 
1600  const auto outputTensor = *it;
1601  try
1602  {
1603  // Check if the output memory can be imported
1604  if (inputTensorHandle->CanBeImported(outputTensor.second.GetMemoryArea(), forceImportMemorySource)
1605  && inputTensorHandle->Import(outputTensor.second.GetMemoryArea(), forceImportMemorySource))
1606  {
1607  importedOutputs.push_back(outputIndex);
1608  }
1609  }
1610  catch(const MemoryImportException& exception)
1611  {
1612  ARMNN_LOG(error) << "An error occurred attempting to import output_"
1613  << outputIndex << " : " << exception.what();
1614  }
1615  outputIndex++;
1616  }
1617  return importedOutputs;
1618  }
1619 
1620  std::vector<ImportedOutputId> importedOutputs;
1621  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1622 
1623  for (const auto& outputTensor : outputTensors)
1624  {
1625  auto layerBindingId = outputTensor.first;
1626  auto it = std::find_if(graph.GetOutputLayers().begin(), graph.GetOutputLayers().end(), [=](auto* layer)
1627  {
1628  return layer->GetBindingId() == layerBindingId;
1629  });
1630 
1631  if (it == graph.GetOutputLayers().end())
1632  {
1633  throw MemoryImportException(fmt::format("ImportOutputs: Memory Import failed, unknown LayerBindingId: {}",
1634  layerBindingId));
1635  }
1636 
1637  const Layer* layer = *it;
1638  if (layer->GetType() != LayerType::Output)
1639  {
1640  throw InvalidArgumentException("ImportOutputs: given layer not an OutputLayer");
1641  }
1642 
1643  auto& backend = m_Backends.at(layer->GetBackendId());
1644  if (!HasCapability(BackendOptions::BackendOption{"PreImportIOTensors", true}, backend->GetCapabilities()))
1645  {
1646  std::string er = backend->GetId();
1647  er += " does not have PreImportIOTensors capability";
1648  throw BackendCapabilityException(er);
1649  }
1650 
1651  const InputSlot& inputSlot = layer->GetInputSlots()[0];
1652  ITensorHandleFactory::FactoryId factoryId = inputSlot.GetConnectedOutputSlot()->GetTensorHandleFactoryId();
1653  const TensorInfo& tensorInfo = inputSlot.GetConnectedOutputSlot()->GetTensorInfo();
1654 
1655  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1656  ARMNN_ASSERT(handleFactory);
1657 
1658  ImportedTensorHandlePin importedTensorHandlePin{layerBindingId,
1659  handleFactory->CreateTensorHandle(tensorInfo, false)};
1660 
1661  ITensorHandle* tensorHandle = importedTensorHandlePin.m_TensorHandle.get();
1662 
1663  if (!CheckFlag(tensorHandle->GetImportFlags(), forceImportMemorySource))
1664  {
1665  throw MemoryImportException(fmt::format("ImportInputs: Memory Import failed, backend: "
1666  "{} does not support importing from source {}"
1667  , factoryId, forceImportMemorySource));
1668  }
1669 
1670  if (tensorHandle->Import(outputTensor.second.GetMemoryArea(), forceImportMemorySource))
1671  {
1672  importedOutputs.push_back(m_CurImportedOutputId++);
1673  }
1674  else
1675  {
1676  throw MemoryImportException("ImportInputs: Memory Import failed");
1677  }
1678 
1679  m_PreImportedOutputHandles.push_back(std::move(importedTensorHandlePin));
1680  }
1681 
1682  return importedOutputs;
1683 }

References ARMNN_ASSERT, ARMNN_LOG, Graph::OutputLayersAccessor::begin(), armnn::CheckFlag(), ITensorHandleFactory::CreateTensorHandle(), Graph::OutputLayersAccessor::end(), armnn::error, Layer::GetBackendId(), InputSlot::GetConnectedOutputSlot(), TensorHandleFactoryRegistry::GetFactory(), ITensorHandle::GetImportFlags(), Layer::GetInputSlots(), Graph::GetOutputLayers(), OutputSlot::GetTensorHandleFactoryId(), OutputSlot::GetTensorInfo(), Layer::GetType(), armnn::HasCapability(), ITensorHandle::Import(), INetworkProperties::m_AsyncEnabled, armnn::Output, armnn::Undefined, and Exception::what().

Referenced by RuntimeImpl::ImportOutputs().

◆ IsAsyncEnabled()

bool IsAsyncEnabled ( )
inline

Definition at line 95 of file LoadedNetwork.hpp.

96  {
97  return m_NetworkProperties.m_AsyncEnabled;
98  }

References INetworkProperties::m_AsyncEnabled.

Referenced by RuntimeImpl::CreateWorkingMemHandle(), RuntimeImpl::EnqueueWorkload(), and RuntimeImpl::Execute().

◆ MakeLoadedNetwork()

std::unique_ptr< LoadedNetwork > MakeLoadedNetwork ( std::unique_ptr< IOptimizedNetwork net,
std::string &  errorMessage,
const INetworkProperties networkProperties,
arm::pipe::IProfilingService *  profilingService 
)
static

Definition at line 170 of file LoadedNetwork.cpp.

174 {
175  std::unique_ptr<LoadedNetwork> loadedNetwork;
176 
177  auto Fail = [&](const std::exception& error) -> std::unique_ptr<LoadedNetwork>
178  {
179  errorMessage = ToErrorMessage("An error occurred when preparing the network workloads: ", error);
180  ARMNN_LOG(error) << errorMessage;
181 
182  return std::unique_ptr<LoadedNetwork>();
183  };
184 
185  try
186  {
187  loadedNetwork.reset(new LoadedNetwork(std::move(net), networkProperties, profilingService));
188  }
189  catch (const armnn::RuntimeException& error)
190  {
191  return Fail(error);
192  }
193  catch (const armnn::Exception& error)
194  {
195  return Fail(error);
196  }
197  catch (const std::runtime_error& error)
198  {
199  return Fail(error);
200  }
201 
202  return loadedNetwork;
203 }

References ARMNN_LOG, and armnn::error.

Referenced by RuntimeImpl::LoadNetwork().

◆ RegisterDebugCallback()

void RegisterDebugCallback ( const DebugCallbackFunction func)

Definition at line 2197 of file LoadedNetwork.cpp.

2198 {
2199  for (auto&& workloadPtr: m_WorkloadQueue)
2200  {
2201  workloadPtr.get()->RegisterDebugCallback(func);
2202  }
2203 }

Referenced by RuntimeImpl::RegisterDebugCallback().

◆ SendNetworkStructure()

void SendNetworkStructure ( arm::pipe::IProfilingService &  profilingService)

Definition at line 654 of file LoadedNetwork.cpp.

655 {
656  ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "LoadNetwork_SendNetworkStructure");
657  Graph& order = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
658  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
659 
660  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
661  TimelineUtilityMethods::GetTimelineUtils(profilingService);
662 
663  timelineUtils->CreateTypedEntity(networkGuid, LabelsAndEventClasses::NETWORK_GUID);
664 
665  for (auto&& layer : order)
666  {
667  // Add layer to the post-optimisation network structure
668  AddLayerStructure(timelineUtils, *layer, networkGuid);
669  switch (layer->GetType())
670  {
671  case LayerType::Input:
672  case LayerType::Output:
673  {
674  // Inputs and outputs are treated in a special way - see EnqueueInput() and EnqueueOutput().
675  break;
676  }
677  default:
678  {
679  for (auto& workload : m_WorkloadQueue)
680  {
681  // Add workload to the post-optimisation network structure
682  AddWorkloadStructure(timelineUtils, workload, *layer);
683  }
684  break;
685  }
686  }
687  }
688  // Commit to send the post-optimisation network structure
689  timelineUtils->Commit();
690 }

References ARMNN_SCOPED_PROFILING_EVENT, armnn::Input, armnn::Output, and armnn::Undefined.


The documentation for this class was generated from the following files:
armnn::MemorySource::Undefined
@ Undefined
armnn::Exception
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
armnn::CopyToOutputTensor
void CopyToOutputTensor(const Tensor &outputTensor, ITensorHandle *outputTensorHandle)
Definition: LoadedNetwork.cpp:1376
armnn::LayerType::Input
@ Input
armnn::INetworkProperties::m_InputSource
const MemorySource m_InputSource
Definition: IRuntime.hpp:72
armnn::LayerBindingId
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:301
armnn::ITensorHandleFactory::LegacyFactoryId
static const FactoryId LegacyFactoryId
Definition: ITensorHandleFactory.hpp:50
armnn::LoadedNetwork::FreeWorkingMemory
void FreeWorkingMemory()
Definition: LoadedNetwork.cpp:1222
armnn::ImportedInputId
unsigned int ImportedInputId
Definition: Types.hpp:302
ARMNN_LOG
#define ARMNN_LOG(severity)
Definition: Logging.hpp:212
armnn::RuntimeException
Definition: Exceptions.hpp:120
armnn::INetworkProperties::m_AsyncEnabled
const bool m_AsyncEnabled
Definition: IRuntime.hpp:66
armnn::Status::Failure
@ Failure
ARMNN_SCOPED_PROFILING_EVENT
#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name)
Definition: Profiling.hpp:220
armnn::TensorHandleFactoryRegistry::ReleaseMemory
void ReleaseMemory()
Release memory required for inference.
Definition: TensorHandleFactoryRegistry.cpp:86
armnn::MemorySource
MemorySource
Define the Memory Source to reduce copies.
Definition: Types.hpp:241
armnn::LoadedNetwork::Execute
Status Execute(const InputTensors &inputTensors, const OutputTensors &outputTensors, IWorkingMemHandle &workingMemHandle, std::vector< ImportedInputId > preImportedInputs={}, std::vector< ImportedOutputId > preImportedOutputs={})
Thread safe execution of the loaded network.
Definition: LoadedNetwork.cpp:1727
armnn::LayerType::Constant
@ Constant
armnn::Status::Success
@ Success
armnn::INetworkProperties::m_ImportEnabled
const bool m_ImportEnabled
Deprecated and will be removed in future release.
Definition: IRuntime.hpp:62
armnn::TensorHandleFactoryRegistry::GetFactory
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
Find a TensorHandleFactory by Id Returns nullptr if not found.
Definition: TensorHandleFactoryRegistry.cpp:39
armnn::Compute::Undefined
@ Undefined
armnn::INetworkProperties::m_ExportEnabled
const bool m_ExportEnabled
Deprecated and will be removed in future release.
Definition: IRuntime.hpp:64
ARMNN_ASSERT_MSG
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
armnn::CheckFlag
bool CheckFlag(MemorySourceFlags flags, MemorySource source)
Definition: MemorySources.hpp:41
ARMNN_NO_DEPRECATE_WARN_BEGIN
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
ARMNN_ASSERT
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
ARMNN_SCOPED_HEAP_PROFILING
#define ARMNN_SCOPED_HEAP_PROFILING(TAG)
Definition: HeapProfiling.hpp:45
armnn::ITensorHandleFactory::FactoryId
std::string FactoryId
Definition: ITensorHandleFactory.hpp:49
armnn::LayerType::Output
@ Output
armnn::LayerType::MemImport
@ MemImport
armnn::BoostLogSeverityMapping::error
@ error
armnn::ImportedOutputId
unsigned int ImportedOutputId
Definition: Types.hpp:303
armnn::HasCapability
bool HasCapability(const std::string &name, const BackendCapabilities &capabilities)
Convenience function to check if a capability exists in a BackendCapabilites struct.
Definition: BackendHelper.cpp:65
armnn::BoostLogSeverityMapping::info
@ info
ARMNN_NO_DEPRECATE_WARN_END
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34