ArmNN
 24.11
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 1768 of file LoadedNetwork.cpp.

1769 {
1770  for (auto id : inputIds)
1771  {
1772  if (id > m_PreImportedInputHandles.size())
1773  {
1774  throw InvalidArgumentException(fmt::format("ClearImportedInputs::Unknown ImportedInputId: {}", id));
1775  }
1776 
1777  auto& importedTensorHandle = m_PreImportedInputHandles[id].m_TensorHandle;
1778  if (!importedTensorHandle)
1779  {
1780  throw InvalidArgumentException(
1781  fmt::format("ClearImportedInputs::ImportedInput with id: {} has already been deleted", id));
1782  }
1783  // Call Unimport then destroy the tensorHandle
1784  importedTensorHandle->Unimport();
1785  importedTensorHandle = {};
1786  }
1787 }

Referenced by RuntimeImpl::ClearImportedInputs().

◆ ClearImportedOutputs()

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

Definition at line 1789 of file LoadedNetwork.cpp.

1790 {
1791  for (auto id : outputIds)
1792  {
1793  if (id > m_PreImportedOutputHandles.size())
1794  {
1795  throw InvalidArgumentException(fmt::format("ClearImportedOutputs::Unknown ImportedOutputId: {}", id));
1796  }
1797 
1798  auto& importedTensorHandle = m_PreImportedOutputHandles[id].m_TensorHandle;
1799  if (!importedTensorHandle)
1800  {
1801  throw InvalidArgumentException(
1802  fmt::format("ClearImportedOutputs::ImportedOutput with id: {} has already been deleted", id));
1803  }
1804  // Call Unimport then destroy the tensorHandle
1805  importedTensorHandle->Unimport();
1806  importedTensorHandle = {};
1807  }
1808 }

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 2032 of file LoadedNetwork.cpp.

2033 {
2034  Graph& order = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
2035 
2036  // Tensors that will need to be allocated internally within armnn
2037  std::vector<std::unique_ptr<ITensorHandle>> managedTensorHandles;
2038  // Tensors that will be allocated externally by the user
2039  std::vector<std::unique_ptr<ITensorHandle>> unmanagedTensorHandles;
2040 
2041  std::vector<WorkingMemDescriptor> workingMemDescriptors;
2042  std::vector<std::pair<BackendId, ExecutionData>> executionDataVec;
2043 
2044  auto GetTensorHandle = [&](Layer* layer, const OutputSlot& outputSlot)
2045  {
2046  ITensorHandleFactory::FactoryId factoryId = outputSlot.GetTensorHandleFactoryId();
2047  const TensorInfo& tensorInfo = outputSlot.GetTensorInfo();
2048 
2049  if (factoryId == ITensorHandleFactory::LegacyFactoryId)
2050  {
2051  BackendId id = layer->GetBackendId();
2053  return m_WorkloadFactories.at(id)->CreateTensorHandle(tensorInfo, false);
2055  }
2056  else
2057  {
2058  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
2059  if (!handleFactory)
2060  {
2061  throw armnn::NullPointerException("handleFactory must not be null.");
2062  }
2063  return handleFactory->CreateTensorHandle(tensorInfo, false);
2064  }
2065  };
2066 
2067  struct HandleInfo
2068  {
2069  ITensorHandle* m_TensorHandle;
2070 
2071  bool m_IsInputLayerHandle = false;
2072  bool m_IsOutputLayerHandle = false;
2073 
2074  WorkingMemHandle::InputMemDescriptorCoords m_InputMemDescriptorCoords;
2075  WorkingMemHandle::OutputMemDescriptorCoords m_OutputMemDescriptorCoords;
2076  };
2077 
2078  std::unordered_map<const OutputSlot*, HandleInfo> outputToHandleInfoMap;
2079 
2080  unsigned int layerIndex = 0;
2081  for (auto&& layer : order)
2082  {
2083  // Constant layers execution and management is handled during loaded network construction
2084  if (layer->GetType() == LayerType::Constant)
2085  {
2086  continue;
2087  }
2088 
2089  WorkingMemDescriptor workingMemDescriptor;
2090 
2091  bool isMemoryManaged = true;
2092  bool isInputLayer = false;
2093  bool isOutputLayer = false;
2094  bool isConnectedToOutputLayer = false;
2095 
2096  if (layer->GetType() == LayerType::Input || layer->GetType() == LayerType::MemImport)
2097  {
2098  // Input layers/workloads will not be executed so the descriptor is not added to workingMemDescriptors
2099  // However we will still need to manage the tensorHandle
2100  isInputLayer = true;
2101  isMemoryManaged = m_NetworkProperties.m_InputSource == MemorySource::Undefined;
2102  }
2103  else if (layer->GetType() == LayerType::Output)
2104  {
2105  isOutputLayer = true;
2106  }
2107 
2108  unsigned int slotIndex = 0;
2109  // Create a tensor handle for each output slot of a layer
2110  // Once we create it, we start managing its lifetime
2111  for (auto& slot : layer->GetOutputSlots())
2112  {
2113  for (unsigned int i = 0; i < slot.GetNumConnections(); ++i)
2114  {
2115  if ((slot.GetConnection(i)->GetOwningLayer().GetType() == LayerType::Output))
2116  {
2117  if (!isConnectedToOutputLayer)
2118  {
2119  isConnectedToOutputLayer = true;
2120  // If Export is enabled disable memory management, so we can export, otherwise we do a copy
2121  isMemoryManaged = m_NetworkProperties.m_OutputSource == MemorySource::Undefined;
2122  }
2123  else
2124  {
2125  // Importing in this case would likely cause unexpected behaviour, so we disallow it.
2126  ARMNN_LOG(warning) <<
2127  fmt::format("Layer name: '{0}' guid: '{1}' has two or more OutputLayers connected to it. "
2128  "This will prevent importing on the connected OutputLayers.",
2129  layer->GetName(), layer->GetGuid());
2130  isMemoryManaged = true;
2131  }
2132  }
2133  }
2134 
2135  ITensorHandle* tensorHandle;
2136  if (isMemoryManaged)
2137  {
2138  managedTensorHandles.emplace_back(GetTensorHandle(layer, slot));
2139  tensorHandle = managedTensorHandles.back().get();
2140  }
2141  else
2142  {
2143  unmanagedTensorHandles.emplace_back(GetTensorHandle(layer, slot));
2144  tensorHandle = unmanagedTensorHandles.back().get();
2145  }
2146 
2147  workingMemDescriptor.m_Outputs.push_back(tensorHandle);
2148 
2149  HandleInfo& handleInfo = outputToHandleInfoMap[&slot];
2150  handleInfo.m_TensorHandle = tensorHandle;
2151 
2152  // Store the coordinates of the current layer's OutputSlot that is connected to the OutputLayer
2153  if (isConnectedToOutputLayer)
2154  {
2155  handleInfo.m_IsOutputLayerHandle = true;
2156  handleInfo.m_OutputMemDescriptorCoords.m_OutputSlotCoords = {layerIndex, slotIndex};
2157  }
2158  // Store the LayerBindingId of the InputLayer
2159  if (isInputLayer)
2160  {
2161  handleInfo.m_IsInputLayerHandle = true;
2162  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
2163  handleInfo.m_InputMemDescriptorCoords.m_LayerBindingId = bindingId;
2164  }
2165  slotIndex++;
2166  }
2167  // Loop through the input slots in the same layer and decrement the reference counter associated
2168  // to each tensor handle we encounter.
2169  // Once it reaches zero, the lifetime of the tensor handle has ended, and we mark its memory as available
2170  // so that the next tensor handle with a non overlapping lifetime can share its memory.
2171  for (auto& slot : layer->GetInputSlots())
2172  {
2173  if (!slot.GetConnection())
2174  {
2175  throw armnn::GraphValidationException("slot must be a valid input slot.");
2176  }
2177 
2178  auto outputSlot = slot.GetConnectedOutputSlot();
2179  auto key = outputSlot->GetOwningLayer().GetGuid();
2180 
2181  // Constant layers execution and management is handled during loaded network construction
2182  auto found = m_ConstantTensorHandles.find(key);
2183  if (found != m_ConstantTensorHandles.end())
2184  {
2185  ITensorHandle* tensorHandle = found->second;
2186  if (slot.IsTensorInfoOverridden())
2187  {
2188  ITensorHandle* decorated = tensorHandle->DecorateTensorHandle(slot.GetTensorInfo()).get();
2189  if (decorated)
2190  {
2191  tensorHandle = decorated;
2192  }
2193  }
2194  workingMemDescriptor.m_Inputs.push_back(tensorHandle);
2195 
2196  // Odd case where a constant layer is connected to an output layer
2197  // We will need to create a HandleInfo to track it
2198  if (isOutputLayer)
2199  {
2200  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
2201 
2202  HandleInfo& handleInfo = outputToHandleInfoMap[outputSlot];
2203  handleInfo.m_TensorHandle = tensorHandle;
2204  handleInfo.m_IsOutputLayerHandle = true;
2205  handleInfo.m_OutputMemDescriptorCoords.m_LayerBindingIds.push_back(bindingId);
2206  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, 0});
2207  }
2208  continue;
2209  }
2210 
2211  HandleInfo& handleInfo = outputToHandleInfoMap.at(outputSlot);
2212 
2213  ITensorHandle* inputTensorHandle = handleInfo.m_TensorHandle;
2214  if (slot.IsTensorInfoOverridden())
2215  {
2216  ITensorHandle* decorated = inputTensorHandle->DecorateTensorHandle(slot.GetTensorInfo()).get();
2217  if (decorated)
2218  {
2219  inputTensorHandle = decorated;
2220  }
2221  }
2222  workingMemDescriptor.m_Inputs.push_back(inputTensorHandle);
2223 
2224  // Store the LayerBindingId of the OutputLayer
2225  if (isOutputLayer)
2226  {
2227  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
2228  handleInfo.m_OutputMemDescriptorCoords.m_LayerBindingIds.push_back(bindingId);
2229  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, 0});
2230  }
2231  // In this case the layer is not an Output Layer but shares its input tensorhandle with an OutputLayer
2232  // It will need to be updated as well, if we swap out the tensorhandle
2233  else if (handleInfo.m_IsOutputLayerHandle)
2234  {
2235  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, slot.GetSlotIndex()});
2236  }
2237 
2238  // Store the coordinates of the InputSlots connected to the InputLayer
2239  // There can be more than one InputSlot connected to an InputLayer, so we use a vector
2240  if (handleInfo.m_IsInputLayerHandle)
2241  {
2242  std::pair<LayerGuid, unsigned int> connectionLocation{layerIndex, slot.GetSlotIndex()};
2243  handleInfo.m_InputMemDescriptorCoords.m_InputSlotCoords.emplace_back(connectionLocation);
2244  }
2245  }
2246 
2247  // Input/Output layers/workloads will not be executed, so the descriptor is not added to workingMemDescriptors
2248  // However we will still need to manage the tensorHandle
2249  if (!isInputLayer)
2250  {
2251  // Simply auto initialise ExecutionData here, so it's added only for the layer that require execution.
2252  // The memory and data will be allocated/assigned for the void* in WorkingMemHandle::Allocate.
2253  std::pair<BackendId, ExecutionData> dataPair;
2254  dataPair.first = layer->GetBackendId();
2255 
2256  executionDataVec.push_back(dataPair);
2257  workingMemDescriptors.push_back(workingMemDescriptor);
2258 
2259  layerIndex++;
2260  }
2261  }
2262 
2263  std::vector<std::pair<std::shared_ptr<TensorMemory>, MemorySource>> tensorMemory;
2264 
2265  auto externalMemoryManager = CreateExternalMemoryManger(tensorMemory);
2266 
2267  // Sort m_TensorMemory, so it's order matches the outputSlot order
2268  std::sort(tensorMemory.begin(), tensorMemory.end(),
2269  [](const std::pair<std::shared_ptr<TensorMemory>, MemorySource>& lhs,
2270  const std::pair<std::shared_ptr<TensorMemory>, MemorySource>& rhs)
2271  {
2272  return lhs.first->m_OutputSlotId < rhs.first->m_OutputSlotId;
2273  });
2274 
2275  std::vector<WorkingMemHandle::InputMemDescriptorCoords> inputConnectionsInfo;
2276  std::vector<WorkingMemHandle::OutputMemDescriptorCoords> outputConnectionsInfo;
2277 
2278  for (const auto& handleInfo: outputToHandleInfoMap)
2279  {
2280  if (handleInfo.second.m_IsOutputLayerHandle)
2281  {
2282  outputConnectionsInfo.emplace_back(handleInfo.second.m_OutputMemDescriptorCoords);
2283  }
2284 
2285  if (handleInfo.second.m_IsInputLayerHandle)
2286  {
2287  inputConnectionsInfo.emplace_back(handleInfo.second.m_InputMemDescriptorCoords);
2288  }
2289  }
2290 
2291  return std::make_unique<WorkingMemHandle>(networkId,
2292  inputConnectionsInfo,
2293  outputConnectionsInfo,
2294  workingMemDescriptors,
2295  std::move(externalMemoryManager),
2296  std::move(tensorMemory),
2297  std::move(managedTensorHandles),
2298  std::move(unmanagedTensorHandles),
2299  executionDataVec,
2300  &m_Backends);
2301 }

References 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 874 of file LoadedNetwork.cpp.

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

References 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 1810 of file LoadedNetwork.cpp.

1815 {
1816  const Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
1817 
1818  if (inputTensors.size() + preImportedInputs.size() != graph.GetNumInputs())
1819  {
1820  if (preImportedInputs.empty())
1821  {
1822  throw InvalidArgumentException("LoadedNetwork::Execute: Number of inputs provided does not match network.");
1823  }
1824  else
1825  {
1826  throw InvalidArgumentException("LoadedNetwork::Execute: "
1827  "Number of inputs + preImportedInputs provided does not match network.");
1828  }
1829  }
1830 
1831  if (outputTensors.size() + preImportedOutputs.size() != graph.GetNumOutputs())
1832  {
1833  if (preImportedOutputs.empty())
1834  {
1835  throw InvalidArgumentException("LoadedNetwork::Execute: "
1836  "Number of outputs provided does not match network.");
1837  }
1838  else
1839  {
1840  throw InvalidArgumentException("LoadedNetwork::Execute: "
1841  "Number of outputs + preImportedOutputs provided does not match network.");
1842  }
1843  }
1844 
1845  WorkingMemHandle& workingMemHandle = dynamic_cast<WorkingMemHandle&>(iWorkingMemHandle);
1846  // Collect all the given LayerBindingIds and check them for duplicates and unknowns.
1847  std::vector<LayerBindingId>& bindingIds = workingMemHandle.GetBindingIdVector();
1848  unsigned int index = 0;
1849  for (auto pair : inputTensors)
1850  {
1851  bindingIds[index++] = pair.first;
1852  }
1853  for (ImportedInputId id : preImportedInputs)
1854  {
1855  bindingIds[index++] = ValidateImportedInputID(id);
1856  }
1857  for (auto pair : outputTensors)
1858  {
1859  bindingIds[index++] = pair.first;
1860  }
1861  for (ImportedOutputId id : preImportedOutputs)
1862  {
1863  bindingIds[index++] = ValidateImportedOutputID(id);
1864  }
1865 
1866  workingMemHandle.ValidateBindingIds();
1867 
1868  auto resetMemHandle = [&]()
1869  {
1870  for (ImportedInputId id: preImportedInputs)
1871  {
1872  const LayerBindingId layerBindingId = m_PreImportedInputHandles[id].m_LayerBindingId;
1873 
1874  auto inputHandle = workingMemHandle.GetInputHandle(layerBindingId);
1875  auto inputConnections = workingMemHandle.GetInputConnections(layerBindingId);
1876  for (auto it : inputConnections)
1877  {
1878  *it = inputHandle;
1879  }
1880  }
1881 
1882  for (ImportedOutputId id: preImportedOutputs)
1883  {
1884  const LayerBindingId layerBindingId = m_PreImportedOutputHandles[id].m_LayerBindingId;
1885 
1886  auto outputHandle = workingMemHandle.GetOutputHandle(layerBindingId);
1887  auto outputConnections = workingMemHandle.GetOutputConnection(layerBindingId);
1888 
1889  for (auto it : outputConnections)
1890  {
1891  *it = outputHandle;
1892  }
1893  }
1894  };
1895 
1896  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
1897  TimelineUtilityMethods::GetTimelineUtils(*m_ProfilingService);
1898  ProfilingGuid inferenceGuid = m_ProfilingService->GetNextGuid();
1899  if (timelineUtils)
1900  {
1901  // Add inference timeline trace if profiling is enabled.
1902  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
1903  timelineUtils->CreateTypedEntity(inferenceGuid,LabelsAndEventClasses::INFERENCE_GUID);
1904  timelineUtils->CreateRelationship(ProfilingRelationshipType::RetentionLink,
1905  networkGuid,
1906  inferenceGuid,
1907  LabelsAndEventClasses::EXECUTION_OF_GUID);
1908  timelineUtils->RecordEvent(inferenceGuid,LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
1909  }
1910 
1911  bool executionSucceeded = true;
1912 
1913  if (timelineUtils)
1914  {
1915  // Add end of life of the inference timeline if profiling is enabled.
1916  timelineUtils->RecordEvent(inferenceGuid,LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
1917  timelineUtils->Commit();
1918  }
1919 
1920  if (!workingMemHandle.IsAllocated())
1921  {
1922  workingMemHandle.Allocate();
1923  }
1924 
1925  {
1927  for (auto pair : inputTensors)
1928  {
1929  EnqueueInput(pair.second, workingMemHandle.GetInputHandle(pair.first));
1930  }
1931 
1932  // Swap in the pre-imported inputs if any
1933  for (ImportedInputId id : preImportedInputs)
1934  {
1935  const ImportedTensorHandlePin& importedInputPin = m_PreImportedInputHandles[id];
1936  const LayerBindingId layerBindingId = m_PreImportedInputHandles[id].m_LayerBindingId;
1937  const auto& preimportedHandle = importedInputPin.m_TensorHandle;
1938 
1939  auto inputConnections = workingMemHandle.GetInputConnections(layerBindingId);
1940  for (auto it : inputConnections)
1941  {
1942  *it = preimportedHandle.get();
1943  }
1944  }
1945  }
1946  {
1948  if (m_NetworkProperties.m_OutputSource != MemorySource::Undefined)
1949  {
1950  for (auto pair: outputTensors)
1951  {
1952  ImportOutputTensor(pair.second, workingMemHandle.GetOutputHandle(pair.first));
1953  }
1954  }
1955 
1956  for (ImportedOutputId id : preImportedOutputs)
1957  {
1958  const ImportedTensorHandlePin& importedOutputPin = m_PreImportedOutputHandles[id];
1959  const LayerBindingId layerBindingId = m_PreImportedOutputHandles[id].m_LayerBindingId;
1960  const auto& preimportedHandle = importedOutputPin.m_TensorHandle;
1961 
1962  auto outputConnections = workingMemHandle.GetOutputConnection(layerBindingId);
1963  for (auto it : outputConnections)
1964  {
1965  *it = preimportedHandle.get();
1966  }
1967  }
1968  }
1969 
1970  auto Fail = [&](const std::exception& error)
1971  {
1972  ARMNN_LOG(error) << "An error occurred attempting to execute a workload: " << error.what();
1973  executionSucceeded = false;
1974  };
1975  ProfilingDynamicGuid workloadInferenceID(0);
1976 
1977  try
1978  {
1979  for (unsigned int i = 0; i < m_WorkloadQueue.size(); ++i)
1980  {
1981  auto& workload = m_WorkloadQueue[i];
1982  if (timelineUtils)
1983  {
1984  workloadInferenceID = timelineUtils->RecordWorkloadInferenceAndStartOfLifeEvent(workload->GetGuid(),
1985  inferenceGuid);
1986  }
1987 
1988  workload->ExecuteAsync(workingMemHandle.GetExecutionDataAt(i).second);
1989 
1990  if (timelineUtils)
1991  {
1992  timelineUtils->RecordEndOfLifeEvent(workloadInferenceID);
1993  }
1994  }
1995  }
1996  catch (const RuntimeException& error)
1997  {
1998  resetMemHandle();
1999  Fail(error);
2000  }
2001  catch (const std::runtime_error& error)
2002  {
2003  resetMemHandle();
2004  Fail(error);
2005  }
2006  catch (...)
2007  {
2008  resetMemHandle();
2009  throw;
2010  }
2011 
2012  if (m_NetworkProperties.m_OutputSource == MemorySource::Undefined)
2013  {
2014  for (auto pair: outputTensors)
2015  {
2016  CopyToOutputTensor(pair.second, workingMemHandle.GetOutputHandle(pair.first));
2017  }
2018  }
2019  else
2020  {
2021  ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "SyncMemGeneric_Execute");
2022  workingMemHandle.MemSyncOutputs();
2023  }
2024 
2025  resetMemHandle();
2026 
2027  return executionSucceeded ? Status::Success : Status::Failure;
2028 }

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_OutputSource, WorkingMemHandle::MemSyncOutputs(), armnn::Success, armnn::Undefined, and WorkingMemHandle::ValidateBindingIds().

Referenced by RuntimeImpl::Execute().

◆ FreeWorkingMemory()

void FreeWorkingMemory ( )

Definition at line 1288 of file LoadedNetwork.cpp.

1289 {
1290 #if !defined(ARMNN_DISABLE_THREADS)
1291  std::lock_guard<std::mutex> lockGuard(m_WorkingMemMutex);
1292 #endif
1293 
1294  if (!m_IsWorkingMemAllocated)
1295  {
1296  return;
1297  }
1298 
1299  if (m_ExternalMemoryManager)
1300  {
1301  m_ExternalMemoryManager->Deallocate();
1302  }
1303 
1304  // Informs the memory managers to release memory in its respective memory group
1305  for (auto&& memoryManager : m_BackendMemoryMangers)
1306  {
1307  if (memoryManager)
1308  {
1309  memoryManager->Release();
1310  }
1311  }
1312  m_TensorHandleFactoryRegistry.ReleaseMemory();
1313  m_IsWorkingMemAllocated = false;
1314 }

References TensorHandleFactoryRegistry::ReleaseMemory().

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

◆ GetInputTensorInfo()

TensorInfo GetInputTensorInfo ( LayerBindingId  layerId) const

Definition at line 717 of file LoadedNetwork.cpp.

718 {
719  for (auto&& inputLayer : m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetInputLayers())
720  {
721  if (inputLayer->GetNumOutputSlots() != 1)
722  {
723  throw armnn::GraphValidationException("Input layer should have exactly 1 output slot");
724  }
725 
726  if (inputLayer->GetBindingId() == layerId)
727  {
728  return inputLayer->GetOutputSlot(0).GetTensorInfo();
729  }
730  }
731 
732  throw InvalidArgumentException(fmt::format("No input layer is associated with id {}", layerId));
733 }

Referenced by RuntimeImpl::GetInputTensorInfo().

◆ GetNetworkGuid()

ProfilingGuid GetNetworkGuid ( )

Definition at line 712 of file LoadedNetwork.cpp.

713 {
714  return m_OptimizedNetwork->GetGuid();
715 }

◆ GetOutputTensorInfo()

TensorInfo GetOutputTensorInfo ( LayerBindingId  layerId) const

Definition at line 735 of file LoadedNetwork.cpp.

736 {
737  for (auto&& outputLayer : m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetOutputLayers())
738  {
739  if (outputLayer->GetNumInputSlots() != 1)
740  {
741  throw armnn::GraphValidationException("Output layer should have exactly 1 input slot");
742  }
743 
744  if (!outputLayer->GetInputSlot(0).GetConnection())
745  {
746  throw armnn::GraphValidationException("Input slot on Output layer must be connected");
747  }
748 
749  if (outputLayer->GetBindingId() == layerId)
750  {
751  return outputLayer->GetInputSlot(0).GetTensorInfo();
752  }
753  }
754 
755  throw InvalidArgumentException(fmt::format("No output layer is associated with id {}", layerId));
756 }

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 1493 of file LoadedNetwork.cpp.

1495 {
1496  if (!m_NetworkProperties.m_AsyncEnabled)
1497  {
1498  // Cannot import if import is not enabled and forceImportMemorySource is undefined
1499  if (forceImportMemorySource == MemorySource::Undefined)
1500  {
1501  throw MemoryImportException("ImportInputs: Memory Import failed, NetworkProperties.m_ImportEnabled");
1502  }
1503  // The number of pre imported tensors should not exceed the number of inputs.
1504  if (inputTensors.size() > m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetNumInputs())
1505  {
1506  throw MemoryImportException("ImportInputs: The number of tensors provided exceeds the number of inputs.");
1507  }
1508 
1509  std::vector<ImportedInputId> importedInputs;
1510  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1511  unsigned int inputIndex = 0;
1512  for (const BindableLayer* inputLayer : graph.GetInputLayers())
1513  {
1514  auto outputTensorHandle = m_PreImportedInputHandles[inputIndex].m_TensorHandle.get();
1515 
1516  if (!outputTensorHandle)
1517  {
1518  inputIndex++;
1519  continue;
1520  }
1521 
1522  auto layerBindingId = inputLayer->GetBindingId();
1523  auto it = std::find_if(inputTensors.begin(), inputTensors.end(), [=](const auto& inputTensor)
1524  {
1525  return inputTensor.first == layerBindingId;
1526  });
1527 
1528  if (it == inputTensors.end())
1529  {
1530  inputIndex++;
1531  continue;
1532  }
1533 
1534  const auto& inputTensor = *it;
1535  std::unique_ptr<ITensorHandle> passThroughTensorHandle =
1536  std::make_unique<ConstPassthroughTensorHandle>(inputTensor.second.GetInfo(),
1537  inputTensor.second.GetMemoryArea());
1538 
1539  try
1540  {
1541  if (outputTensorHandle->CanBeImported(passThroughTensorHandle->Map(), forceImportMemorySource)
1542  && (outputTensorHandle->Import(passThroughTensorHandle->Map(), forceImportMemorySource)))
1543  {
1544  importedInputs.push_back(inputIndex);
1545  }
1546  passThroughTensorHandle->Unmap();
1547  }
1548  catch(const MemoryImportException& exception)
1549  {
1550  ARMNN_LOG(error) << "An error occurred attempting to import input_"
1551  << inputIndex << " : " << exception.what();
1552  passThroughTensorHandle->Unmap();
1553  }
1554  inputIndex++;
1555  }
1556 
1557  return importedInputs;
1558  }
1559  else
1560  {
1561  // Import when the import of network properties is enabled
1562  std::vector<ImportedInputId> importedInputs;
1563  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1564 
1565  for (auto inputTensor : inputTensors)
1566  {
1567  auto layerBindingId = inputTensor.first;
1568  auto it = std::find_if(graph.GetInputLayers().begin(), graph.GetInputLayers().end(), [=](auto* layer)
1569  {
1570  return layer->GetBindingId() == layerBindingId;
1571  });
1572 
1573  if (it == graph.GetInputLayers().end())
1574  {
1575  throw MemoryImportException(fmt::format(
1576  "ImportInputs: Memory Import failed, unknown LayerBindingId: {}", layerBindingId));
1577  }
1578 
1579  const Layer* layer = *it;
1580  if (layer->GetType() != LayerType::Input)
1581  {
1582  throw InvalidArgumentException("ImportInputs: given layer not an InputLayer");
1583  }
1584 
1585  auto& backend = m_Backends.at(layer->GetBackendId());
1586  if (!HasMatchingCapability(BackendOptions::BackendOption{"PreImportIOTensors", true},
1587  backend->GetCapabilities()))
1588  {
1589  std::string er = backend->GetId();
1590  er += " does not have PreImportIOTensors capability";
1591  throw BackendCapabilityException(er);
1592  }
1593 
1594  const OutputSlot& outputSlot = layer->GetOutputSlots()[0];
1595 
1596  ITensorHandleFactory::FactoryId factoryId = outputSlot.GetTensorHandleFactoryId();
1597  const TensorInfo& tensorInfo = outputSlot.GetTensorInfo();
1598 
1599  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1600  if (!handleFactory)
1601  {
1602  throw armnn::NullPointerException("handleFactory must not be null.");
1603  }
1604 
1605  ImportedTensorHandlePin importedTensorHandlePin{layerBindingId,
1606  handleFactory->CreateTensorHandle(tensorInfo, false)};
1607 
1608  ITensorHandle* tensorHandle = importedTensorHandlePin.m_TensorHandle.get();
1609 
1610  if (!CheckFlag(tensorHandle->GetImportFlags(), forceImportMemorySource))
1611  {
1612  throw MemoryImportException(
1613  fmt::format("ImportInputs: Memory Import failed, backend: "
1614  "{} does not support importing from source {}"
1615  , factoryId, m_NetworkProperties.m_InputSource));
1616  }
1617 
1618  std::unique_ptr<ITensorHandle> passThroughTensorHandle =
1619  std::make_unique<ConstPassthroughTensorHandle>(inputTensor.second.GetInfo(),
1620  inputTensor.second.GetMemoryArea());
1621 
1622  if (tensorHandle->Import(passThroughTensorHandle->Map(), forceImportMemorySource))
1623  {
1624  importedInputs.push_back(m_CurImportedInputId++);
1625  passThroughTensorHandle->Unmap();
1626  }
1627  else
1628  {
1629  passThroughTensorHandle->Unmap();
1630  throw MemoryImportException("ImportInputs: Memory Import failed");
1631  }
1632 
1633  m_PreImportedInputHandles.push_back(std::move(importedTensorHandlePin));
1634  }
1635  return importedInputs;
1636  }
1637 }

References 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::HasMatchingCapability(), 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 1639 of file LoadedNetwork.cpp.

1641 {
1642  if (!m_NetworkProperties.m_AsyncEnabled)
1643  {
1644  // Cannot import if import is not enabled and forceImportMemorySource is undefined
1645  if (forceImportMemorySource == MemorySource::Undefined)
1646  {
1647  throw MemoryImportException("ImportOutputs: Memory Import failed, NetworkProperties.m_ImportEnabled");
1648  }
1649  // If forceImportMemorySource is defined, try import if memory is aligned
1650  if (outputTensors.size() != m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetNumOutputs())
1651  {
1652  throw MemoryImportException("ImportOutputs: Force Import failed, incorrect number of tensors");
1653  }
1654  std::vector<ImportedOutputId> importedOutputs;
1655  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1656 
1657  unsigned int outputIndex = 0;
1658  for (const BindableLayer* const outputLayer : graph.GetOutputLayers())
1659  {
1660  auto inputTensorHandle = m_PreImportedOutputHandles[outputIndex].m_TensorHandle.get();
1661  if (!inputTensorHandle)
1662  {
1663  outputIndex++;
1664  continue;
1665  }
1666 
1667  auto layerBindingId = outputLayer->GetBindingId();
1668  auto it = std::find_if(outputTensors.begin(), outputTensors.end(), [=] (const auto& outputTensor)
1669  {
1670  return outputTensor.first == layerBindingId;
1671  });
1672 
1673  if (it == outputTensors.end())
1674  {
1675  outputIndex++;
1676  continue;
1677  }
1678 
1679  const auto outputTensor = *it;
1680  try
1681  {
1682  // Check if the output memory can be imported
1683  if (inputTensorHandle->CanBeImported(outputTensor.second.GetMemoryArea(), forceImportMemorySource)
1684  && inputTensorHandle->Import(outputTensor.second.GetMemoryArea(), forceImportMemorySource))
1685  {
1686  importedOutputs.push_back(outputIndex);
1687  }
1688  }
1689  catch(const MemoryImportException& exception)
1690  {
1691  ARMNN_LOG(error) << "An error occurred attempting to import output_"
1692  << outputIndex << " : " << exception.what();
1693  }
1694  outputIndex++;
1695  }
1696  return importedOutputs;
1697  }
1698 
1699  std::vector<ImportedOutputId> importedOutputs;
1700  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1701 
1702  for (const auto& outputTensor : outputTensors)
1703  {
1704  auto layerBindingId = outputTensor.first;
1705  auto it = std::find_if(graph.GetOutputLayers().begin(), graph.GetOutputLayers().end(), [=](auto* layer)
1706  {
1707  return layer->GetBindingId() == layerBindingId;
1708  });
1709 
1710  if (it == graph.GetOutputLayers().end())
1711  {
1712  throw MemoryImportException(fmt::format("ImportOutputs: Memory Import failed, unknown LayerBindingId: {}",
1713  layerBindingId));
1714  }
1715 
1716  const Layer* layer = *it;
1717  if (layer->GetType() != LayerType::Output)
1718  {
1719  throw InvalidArgumentException("ImportOutputs: given layer not an OutputLayer");
1720  }
1721 
1722  auto& backend = m_Backends.at(layer->GetBackendId());
1723  if (!HasMatchingCapability(BackendOptions::BackendOption{"PreImportIOTensors", true},
1724  backend->GetCapabilities()))
1725  {
1726  std::string er = backend->GetId();
1727  er += " does not have PreImportIOTensors capability";
1728  throw BackendCapabilityException(er);
1729  }
1730 
1731  const InputSlot& inputSlot = layer->GetInputSlots()[0];
1732  ITensorHandleFactory::FactoryId factoryId = inputSlot.GetConnectedOutputSlot()->GetTensorHandleFactoryId();
1733  const TensorInfo& tensorInfo = inputSlot.GetTensorInfo();
1734 
1735  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1736  if (!handleFactory)
1737  {
1738  throw armnn::NullPointerException("handleFactory must not be null.");
1739  }
1740 
1741  ImportedTensorHandlePin importedTensorHandlePin{layerBindingId,
1742  handleFactory->CreateTensorHandle(tensorInfo, false)};
1743 
1744  ITensorHandle* tensorHandle = importedTensorHandlePin.m_TensorHandle.get();
1745 
1746  if (!CheckFlag(tensorHandle->GetImportFlags(), forceImportMemorySource))
1747  {
1748  throw MemoryImportException(fmt::format("ImportInputs: Memory Import failed, backend: "
1749  "{} does not support importing from source {}"
1750  , factoryId, forceImportMemorySource));
1751  }
1752 
1753  if (tensorHandle->Import(outputTensor.second.GetMemoryArea(), forceImportMemorySource))
1754  {
1755  importedOutputs.push_back(m_CurImportedOutputId++);
1756  }
1757  else
1758  {
1759  throw MemoryImportException("ImportInputs: Memory Import failed");
1760  }
1761 
1762  m_PreImportedOutputHandles.push_back(std::move(importedTensorHandlePin));
1763  }
1764 
1765  return importedOutputs;
1766 }

References 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(), InputSlot::GetTensorInfo(), Layer::GetType(), armnn::HasMatchingCapability(), 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 174 of file LoadedNetwork.cpp.

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

References ARMNN_LOG, and armnn::error.

Referenced by RuntimeImpl::LoadNetwork().

◆ RegisterDebugCallback()

void RegisterDebugCallback ( const DebugCallbackFunction func)

Definition at line 2303 of file LoadedNetwork.cpp.

2304 {
2305  for (auto&& workloadPtr: m_WorkloadQueue)
2306  {
2307  workloadPtr.get()->RegisterDebugCallback(func);
2308  }
2309 }

Referenced by RuntimeImpl::RegisterDebugCallback().

◆ SendNetworkStructure()

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

Definition at line 674 of file LoadedNetwork.cpp.

675 {
676  ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "LoadNetwork_SendNetworkStructure");
677  Graph& order = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
678  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
679 
680  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
681  TimelineUtilityMethods::GetTimelineUtils(profilingService);
682 
683  timelineUtils->CreateTypedEntity(networkGuid, LabelsAndEventClasses::NETWORK_GUID);
684 
685  for (auto&& layer : order)
686  {
687  // Add layer to the post-optimisation network structure
688  AddLayerStructure(timelineUtils, *layer, networkGuid);
689  switch (layer->GetType())
690  {
691  case LayerType::Input:
692  case LayerType::Output:
693  {
694  // Inputs and outputs are treated in a special way - see EnqueueInput() and EnqueueOutput().
695  break;
696  }
697  default:
698  {
699  for (auto& workload : m_WorkloadQueue)
700  {
701  // Add workload to the post-optimisation network structure
702  AddWorkloadStructure(timelineUtils, workload, *layer);
703  }
704  break;
705  }
706  }
707  }
708  // Commit to send the post-optimisation network structure
709  timelineUtils->Commit();
710 }

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


The documentation for this class was generated from the following files:
armnn::ImportedInputId
unsigned int ImportedInputId
Definition: Types.hpp:315
armnn::Compute::Undefined
@ Undefined
armnn::INetworkProperties::m_AsyncEnabled
const bool m_AsyncEnabled
Definition: IRuntime.hpp:59
armnn::INetworkProperties::m_InputSource
const MemorySource m_InputSource
Definition: IRuntime.hpp:65
armnn::TensorHandleFactoryRegistry::ReleaseMemory
void ReleaseMemory()
Release memory required for inference.
Definition: TensorHandleFactoryRegistry.cpp:86
armnn::TensorHandleFactoryRegistry::GetFactory
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
Find a TensorHandleFactory by Id Returns nullptr if not found.
Definition: TensorHandleFactoryRegistry.cpp:39
ARMNN_NO_DEPRECATE_WARN_BEGIN
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
armnn::BoostLogSeverityMapping::error
@ error
armnn::ITensorHandleFactory::LegacyFactoryId
static const FactoryId LegacyFactoryId
Definition: ITensorHandleFactory.hpp:50
ARMNN_LOG
#define ARMNN_LOG(severity)
Definition: Logging.hpp:212
ARMNN_SCOPED_PROFILING_EVENT
#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name)
Definition: Profiling.hpp:220
armnn::MemorySource::Undefined
@ Undefined
armnn::LayerBindingId
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:314
armnn::CopyToOutputTensor
void CopyToOutputTensor(const Tensor &outputTensor, ITensorHandle *outputTensorHandle)
Definition: LoadedNetwork.cpp:1451
ARMNN_SCOPED_HEAP_PROFILING
#define ARMNN_SCOPED_HEAP_PROFILING(TAG)
Definition: HeapProfiling.hpp:45
armnn::CheckFlag
bool CheckFlag(MemorySourceFlags flags, MemorySource source)
Definition: MemorySources.hpp:41
armnn::Status::Success
@ Success
armnn::Exception
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
armnn::RuntimeException
Definition: Exceptions.hpp:120
armnn::BoostLogSeverityMapping::info
@ info
armnn::LayerType::MemImport
@ MemImport
armnn::ImportedOutputId
unsigned int ImportedOutputId
Definition: Types.hpp:316
ARMNN_NO_DEPRECATE_WARN_END
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
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:1810
armnn::MemorySource
MemorySource
Define the Memory Source to reduce copies.
Definition: Types.hpp:245
armnn::GraphValidationException
Definition: Exceptions.hpp:110
armnn::LoadedNetwork::FreeWorkingMemory
void FreeWorkingMemory()
Definition: LoadedNetwork.cpp:1288
armnn::ITensorHandleFactory::FactoryId
std::string FactoryId
Definition: ITensorHandleFactory.hpp:49
armnn::LayerType::Input
@ Input
armnn::NullPointerException
Definition: Exceptions.hpp:146
armnn::INetworkProperties::m_OutputSource
const MemorySource m_OutputSource
Definition: IRuntime.hpp:66
armnn::Status::Failure
@ Failure
armnn::LayerType::Output
@ Output
armnn::LayerType::Constant
@ Constant
armnn::HasMatchingCapability
bool HasMatchingCapability(const BackendOptions::BackendOption &capability, const BackendCapabilities &capabilities)
Convenience function to check if a given capability matches a capability in a BackendCapabilities str...
Definition: BackendHelper.cpp:85