ArmNN
 22.05.01
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  }

Member Function Documentation

◆ ClearImportedInputs()

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

Definition at line 1586 of file LoadedNetwork.cpp.

Referenced by RuntimeImpl::ClearImportedInputs().

1587 {
1588  for (auto id : inputIds)
1589  {
1590  if (id > m_PreImportedInputHandles.size())
1591  {
1592  throw InvalidArgumentException(fmt::format("ClearImportedInputs::Unknown ImportedInputId: {}", id));
1593  }
1594 
1595  auto& importedTensorHandle = m_PreImportedInputHandles[id].m_TensorHandle;
1596  if (!importedTensorHandle)
1597  {
1598  throw InvalidArgumentException(
1599  fmt::format("ClearImportedInputs::ImportedInput with id: {} has already been deleted", id));
1600  }
1601  // Call Unimport then destroy the tensorHandle
1602  importedTensorHandle->Unimport();
1603  importedTensorHandle = {};
1604  }
1605 }

◆ ClearImportedOutputs()

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

Definition at line 1607 of file LoadedNetwork.cpp.

Referenced by RuntimeImpl::ClearImportedOutputs().

1608 {
1609  for (auto id : outputIds)
1610  {
1611  if (id > m_PreImportedOutputHandles.size())
1612  {
1613  throw InvalidArgumentException(fmt::format("ClearImportedOutputs::Unknown ImportedOutputId: {}", id));
1614  }
1615 
1616  auto& importedTensorHandle = m_PreImportedOutputHandles[id].m_TensorHandle;
1617  if (!importedTensorHandle)
1618  {
1619  throw InvalidArgumentException(
1620  fmt::format("ClearImportedOutputs::ImportedOutput with id: {} has already been deleted", id));
1621  }
1622  // Call Unimport then destroy the tensorHandle
1623  importedTensorHandle->Unimport();
1624  importedTensorHandle = {};
1625  }
1626 }

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

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

Referenced by RuntimeImpl::CreateWorkingMemHandle().

1851 {
1852  Graph& order = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
1853 
1854  // Tensors that will need to be allocated internally within armnn
1855  std::vector<std::unique_ptr<ITensorHandle>> managedTensorHandles;
1856  // Tensors that will be allocated externally by the user
1857  std::vector<std::unique_ptr<ITensorHandle>> unmanagedTensorHandles;
1858 
1859  std::vector<WorkingMemDescriptor> workingMemDescriptors;
1860  std::unordered_map<LayerGuid, WorkingMemDescriptor> workingMemDescriptorMap;
1861 
1862  auto GetTensorHandle = [&](Layer* layer, const OutputSlot& outputSlot)
1863  {
1864  ITensorHandleFactory::FactoryId factoryId = outputSlot.GetTensorHandleFactoryId();
1865  const TensorInfo& tensorInfo = outputSlot.GetTensorInfo();
1866 
1867  if (factoryId == ITensorHandleFactory::LegacyFactoryId)
1868  {
1869  BackendId id = layer->GetBackendId();
1871  return m_WorkloadFactories.at(id)->CreateTensorHandle(tensorInfo, false);
1873  }
1874  else
1875  {
1876  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1877  ARMNN_ASSERT(handleFactory);
1878  return handleFactory->CreateTensorHandle(tensorInfo, false);
1879  }
1880  };
1881 
1882  struct HandleInfo
1883  {
1884  ITensorHandle* m_TensorHandle;
1885 
1886  bool m_IsInputLayerHandle = false;
1887  bool m_IsOutputLayerHandle = false;
1888 
1889  WorkingMemHandle::InputMemDescriptorCoords m_InputMemDescriptorCoords;
1890  WorkingMemHandle::OutputMemDescriptorCoords m_OutputMemDescriptorCoords;
1891  };
1892 
1893  std::unordered_map<const OutputSlot*, HandleInfo> outputToHandleInfoMap;
1894 
1895  unsigned int layerIndex = 0;
1896  for (auto&& layer : order)
1897  {
1898  // Constant layers execution and management is handled during loaded network construction
1899  if (layer->GetType() == LayerType::Constant)
1900  {
1901  continue;
1902  }
1903 
1904  WorkingMemDescriptor workingMemDescriptor;
1905 
1906  bool isMemoryManaged = true;
1907  bool isInputLayer = false;
1908  bool isOutputLayer = false;
1909  bool isConnectedToOutputLayer = false;
1910 
1911  if (layer->GetType() == LayerType::Input || layer->GetType() == LayerType::MemImport)
1912  {
1913  // Input layers/workloads will not be executed so the descriptor is not added to workingMemDescriptors
1914  // However we will still need to manage the tensorHandle
1915  isInputLayer = true;
1916  isMemoryManaged = !m_NetworkProperties.m_ImportEnabled;
1917  }
1918  else if (layer->GetType() == LayerType::Output)
1919  {
1920  isOutputLayer = true;
1921  }
1922 
1923  unsigned int slotIndex = 0;
1924  // Create a tensor handle for each output slot of a layer
1925  // Once we create it, we start managing its lifetime
1926  for (auto& slot : layer->GetOutputSlots())
1927  {
1928  for (unsigned int i = 0; i < slot.GetNumConnections(); ++i)
1929  {
1930  if ((slot.GetConnection(i)->GetOwningLayer().GetType() == LayerType::Output))
1931  {
1932  if (!isConnectedToOutputLayer)
1933  {
1934  isConnectedToOutputLayer = true;
1935  // If Export is enabled disable memory management, so we can export, otherwise we do a copy
1936  isMemoryManaged = !m_NetworkProperties.m_ExportEnabled;
1937  }
1938  else
1939  {
1940  // Importing in this case would likely cause unexpected behaviour, so we disallow it.
1941  ARMNN_LOG(warning) <<
1942  fmt::format("Layer name: '{0}' guid: '{1}' has two or more OutputLayers connected to it. "
1943  "This will prevent importing on the connected OutputLayers.",
1944  layer->GetName(), layer->GetGuid());
1945  isMemoryManaged = true;
1946  }
1947  }
1948  }
1949 
1950  ITensorHandle* tensorHandle;
1951  if (isMemoryManaged)
1952  {
1953  managedTensorHandles.emplace_back(GetTensorHandle(layer, slot));
1954  tensorHandle = managedTensorHandles.back().get();
1955  }
1956  else
1957  {
1958  unmanagedTensorHandles.emplace_back(GetTensorHandle(layer, slot));
1959  tensorHandle = unmanagedTensorHandles.back().get();
1960  }
1961 
1962  workingMemDescriptor.m_Outputs.push_back(tensorHandle);
1963 
1964  HandleInfo& handleInfo = outputToHandleInfoMap[&slot];
1965  handleInfo.m_TensorHandle = tensorHandle;
1966 
1967  // Store the coordinates of the current layer's OutputSlot that is connected to the OutputLayer
1968  if (isConnectedToOutputLayer)
1969  {
1970  handleInfo.m_IsOutputLayerHandle = true;
1971  handleInfo.m_OutputMemDescriptorCoords.m_OutputSlotCoords = {layerIndex, slotIndex};
1972  }
1973  // Store the LayerBindingId of the InputLayer
1974  if (isInputLayer)
1975  {
1976  handleInfo.m_IsInputLayerHandle = true;
1977  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
1978  handleInfo.m_InputMemDescriptorCoords.m_LayerBindingId = bindingId;
1979  }
1980  slotIndex++;
1981  }
1982  // Loop through the input slots in the same layer and decrement the reference counter associated
1983  // to each tensor handle we encounter.
1984  // Once it reaches zero, the lifetime of the tensor handle has ended, and we mark its memory as available
1985  // so that the next tensor handle with a non overlapping lifetime can share its memory.
1986  for (auto& slot : layer->GetInputSlots())
1987  {
1988  ARMNN_ASSERT(slot.GetConnection());
1989  auto outputSlot = slot.GetConnectedOutputSlot();
1990  auto key = outputSlot->GetOwningLayer().GetGuid();
1991 
1992  // Constant layers execution and management is handled during loaded network construction
1993  auto found = m_ConstantTensorHandles.find(key);
1994  if (found != m_ConstantTensorHandles.end())
1995  {
1996  ITensorHandle* tensorHandle = found->second;
1997  workingMemDescriptor.m_Inputs.push_back(tensorHandle);
1998 
1999  // Odd case where a constant layer is connected to an output layer
2000  // We will need to create a HandleInfo to track it
2001  if (isOutputLayer)
2002  {
2003  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
2004 
2005  HandleInfo& handleInfo = outputToHandleInfoMap[outputSlot];
2006  handleInfo.m_TensorHandle = tensorHandle;
2007  handleInfo.m_IsOutputLayerHandle = true;
2008  handleInfo.m_OutputMemDescriptorCoords.m_LayerBindingIds.push_back(bindingId);
2009  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, 0});
2010  }
2011  continue;
2012  }
2013 
2014  HandleInfo& handleInfo = outputToHandleInfoMap.at(outputSlot);
2015 
2016  ITensorHandle* inputTensorHandle = handleInfo.m_TensorHandle;
2017  workingMemDescriptor.m_Inputs.push_back(inputTensorHandle);
2018 
2019  // Store the LayerBindingId of the OutputLayer
2020  if (isOutputLayer)
2021  {
2022  LayerBindingId bindingId = static_cast<BindableLayer*>(layer)->GetBindingId();
2023  handleInfo.m_OutputMemDescriptorCoords.m_LayerBindingIds.push_back(bindingId);
2024  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, 0});
2025  }
2026  // In this case the layer is not an Output Layer but shares its input tensorhandle with an OutputLayer
2027  // It will need to be updated as well, if we swap out the tensorhandle
2028  else if (handleInfo.m_IsOutputLayerHandle)
2029  {
2030  handleInfo.m_OutputMemDescriptorCoords.m_InputSlotCoords.push_back({layerIndex, slot.GetSlotIndex()});
2031  }
2032 
2033  // Store the coordinates of the InputSlots connected to the InputLayer
2034  // There can be more than one InputSlot connected to an InputLayer, so we use a vector
2035  if (handleInfo.m_IsInputLayerHandle)
2036  {
2037  std::pair<LayerGuid, unsigned int> connectionLocation{layerIndex, slot.GetSlotIndex()};
2038  handleInfo.m_InputMemDescriptorCoords.m_InputSlotCoords.emplace_back(connectionLocation);
2039  }
2040  }
2041  workingMemDescriptorMap.insert({layer->GetGuid(), workingMemDescriptor});
2042 
2043  // Input/Output layers/workloads will not be executed, so the descriptor is not added to workingMemDescriptors
2044  // However we will still need to manage the tensorHandle
2045  if (!isInputLayer)
2046  {
2047  workingMemDescriptors.push_back(workingMemDescriptor);
2048  layerIndex++;
2049  }
2050  }
2051 
2052  std::vector<std::pair<std::shared_ptr<TensorMemory>, MemorySource>> tensorMemory;
2053 
2054  auto externalMemoryManager = CreateExternalMemoryManger(tensorMemory);
2055 
2056  // Sort m_TensorMemory, so it's order matches the outputSlot order
2057  std::sort(tensorMemory.begin(), tensorMemory.end(),
2058  [](const std::pair<std::shared_ptr<TensorMemory>, MemorySource>& lhs,
2059  const std::pair<std::shared_ptr<TensorMemory>, MemorySource>& rhs)
2060  {
2061  return lhs.first->m_OutputSlotId < rhs.first->m_OutputSlotId;
2062  });
2063 
2064  std::vector<WorkingMemHandle::InputMemDescriptorCoords> inputConnectionsInfo;
2065  std::vector<WorkingMemHandle::OutputMemDescriptorCoords> outputConnectionsInfo;
2066 
2067  for (const auto& handleInfo: outputToHandleInfoMap)
2068  {
2069  if (handleInfo.second.m_IsOutputLayerHandle)
2070  {
2071  outputConnectionsInfo.emplace_back(handleInfo.second.m_OutputMemDescriptorCoords);
2072  }
2073 
2074  if (handleInfo.second.m_IsInputLayerHandle)
2075  {
2076  inputConnectionsInfo.emplace_back(handleInfo.second.m_InputMemDescriptorCoords);
2077  }
2078  }
2079 
2080  return std::make_unique<WorkingMemHandle>(networkId,
2081  inputConnectionsInfo,
2082  outputConnectionsInfo,
2083  workingMemDescriptors,
2084  workingMemDescriptorMap,
2085  std::move(externalMemoryManager),
2086  std::move(tensorMemory),
2087  std::move(managedTensorHandles),
2088  std::move(unmanagedTensorHandles));
2089 }
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
#define ARMNN_LOG(severity)
Definition: Logging.hpp:205
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:290
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
MemorySource
Define the Memory Source to reduce copies.
Definition: Types.hpp:230
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
Find a TensorHandleFactory by Id Returns nullptr if not found.
static const FactoryId LegacyFactoryId

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

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, WorkloadInfo::m_InputTensorInfos, armnn::Undefined, and armnn::warning.

Referenced by RuntimeImpl::EnqueueWorkload().

759 {
760  const Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
761 
762  // Walk graph to determine the order of execution.
763  if (graph.GetNumLayers() < 2)
764  {
765  ARMNN_LOG(warning) << "IRuntime::EnqueueWorkload()::Less than two nodes in graph";
766  return Status::Failure;
767  }
768 
769  // Data that must be kept alive for the entire execution of the workload.
770  WorkloadData workloadData(inputTensors, outputTensors);
771 
772  if (graph.GetNumInputs() != inputTensors.size())
773  {
774  throw InvalidArgumentException("Number of inputs provided does not match network.");
775  }
776 
777  // For each input to the network, call EnqueueInput with the data passed by the user.
778  {
780  m_InputQueue.clear();
781  m_InputQueue.reserve(graph.GetNumInputs());
782 
783  if (preImportedInputIds.size() > graph.GetNumInputs())
784  {
785  throw InvalidArgumentException("Invalid number of preImportedInputIds");
786  }
787 
788  unsigned int inputIndex = 0;
789  unsigned int importedInputIdIndex = 0;
790  std::sort(preImportedInputIds.begin(), preImportedInputIds.end());
791  for (const BindableLayer* inputLayer : graph.GetInputLayers())
792  {
793  if (importedInputIdIndex < preImportedInputIds.size() &&
794  inputIndex == preImportedInputIds[importedInputIdIndex])
795  {
796  // Only replace tensorhandles if they have not already been replaced
797  if (!m_IsInputImported[inputIndex])
798  {
799  auto outputTensorHandle = m_PreImportedInputHandles[inputIndex].m_TensorHandle.get();
800 
801  for (const auto& workloadInfo: m_InputWorkloadSlotPairs[inputLayer->GetBindingId()])
802  {
803  auto workload = m_WorkloadQueue[workloadInfo.m_WorkloadIndex].get();
804  workload->ReplaceInputTensorHandle(outputTensorHandle, workloadInfo.m_SlotIndex);
805  }
806  m_IsInputImported[inputIndex] = true;
807  }
808  importedInputIdIndex++;
809  }
810  else
811  {
812  if (m_IsInputImported[inputIndex])
813  {
814  OutputHandler& handler = const_cast<OutputHandler&>(inputLayer->GetOutputHandler(0));
815 
816  for (const auto& workloadInfo: m_InputWorkloadSlotPairs[inputLayer->GetBindingId()])
817  {
818  auto workload = m_WorkloadQueue[workloadInfo.m_WorkloadIndex].get();
819  workload->ReplaceInputTensorHandle(handler.GetData(), workloadInfo.m_SlotIndex);
820  }
821 
822  m_IsInputImported[inputIndex] = false;
823  }
824 
825  // InputTensorHandle is not imported yet, process to enqueue input
826  const TensorPin& pin = workloadData.GetInputTensorPin(inputLayer->GetBindingId());
827  EnqueueInput(*inputLayer, pin.GetTensorHandle(), pin.GetTensorInfo());
828  }
829  inputIndex++;
830  }
831  }
832  // For each output to the network, call EnqueueOutput with the data passed by the user.
833  {
835  m_OutputQueue.clear();
836  m_OutputQueue.reserve(graph.GetNumOutputs());
837 
838  if (preImportedOutputIds.size() > graph.GetNumOutputs())
839  {
840  throw InvalidArgumentException("Invalid number of preImportedOutputIds");
841  }
842 
843  unsigned int outputIndex = 0;
844  unsigned int importedOutputIdIndex = 0;
845  std::sort(preImportedOutputIds.begin(), preImportedOutputIds.end());
846  for (const BindableLayer* outputLayer : graph.GetOutputLayers())
847  {
848  if (importedOutputIdIndex < preImportedOutputIds.size() &&
849  outputIndex == preImportedOutputIds[importedOutputIdIndex])
850  {
851  // Only replace tensorhandles if they have not already been replaced
852  ITensorHandle* inputTensorHandle = m_PreImportedOutputHandles[outputIndex].m_TensorHandle.get();
853 
854  if (!m_IsOutputImported[outputIndex])
855  {
856  const auto bindingId = outputLayer->GetBindingId();
857  const auto& indices = m_OutputWorkloadSlotPairs[bindingId];
858 
859  auto outputWorkload = m_WorkloadQueue[indices.m_OutputSlotIndices.m_WorkloadIndex].get();
860 
861  outputWorkload->ReplaceOutputTensorHandle(inputTensorHandle,
862  indices.m_OutputSlotIndices.m_SlotIndex);
863 
864  for (const auto& workloadInfo: indices.m_InputSlotIndices)
865  {
866  auto inputWorkload = m_WorkloadQueue[workloadInfo.m_WorkloadIndex].get();
867  inputWorkload->ReplaceInputTensorHandle(inputTensorHandle, workloadInfo.m_SlotIndex);
868  }
869  m_IsOutputImported[outputIndex] = true;
870  }
871 
872  ARMNN_ASSERT_MSG(inputTensorHandle != nullptr, "Data should have been allocated.");
873  MemSyncQueueDescriptor syncDesc;
874  syncDesc.m_Inputs.push_back(inputTensorHandle);
875  WorkloadInfo info;
876  info.m_InputTensorInfos.push_back(
877  outputLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo());
878  auto syncWorkload = std::make_unique<SyncMemGenericWorkload>(syncDesc, info);
879  ARMNN_ASSERT_MSG(syncWorkload, "No sync workload created");
880  m_OutputQueue.push_back(move(syncWorkload));
881  importedOutputIdIndex++;
882  }
883  else
884  {
885  if (m_IsOutputImported[outputIndex])
886  {
887  const auto bindingId = outputLayer->GetBindingId();
888  const auto& indices = m_OutputWorkloadSlotPairs[bindingId];
889 
890  auto outputWorkload = m_WorkloadQueue[indices.m_OutputSlotIndices.m_WorkloadIndex].get();
891  const OutputHandler& outputHandler =
892  outputLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetOutputHandler();
893 
894  outputWorkload->ReplaceOutputTensorHandle(
895  outputHandler.GetData(), indices.m_OutputSlotIndices.m_SlotIndex);
896 
897  for (const auto& workloadInfo: indices.m_InputSlotIndices)
898  {
899  auto inputWorkload = m_WorkloadQueue[workloadInfo.m_WorkloadIndex].get();
900  inputWorkload->ReplaceInputTensorHandle(outputHandler.GetData(), workloadInfo.m_SlotIndex);
901  }
902  m_IsOutputImported[outputIndex] = false;
903  }
904 
905  const TensorPin& pin = workloadData.GetOutputTensorPin(outputLayer->GetBindingId());
906  // OutputTensorHandle is not imported yet, process to enqueue Output
907  EnqueueOutput(*outputLayer, pin.GetTensorHandle(), pin.GetTensorInfo());
908  }
909  outputIndex++;
910  }
911  }
912 
913  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
914  TimelineUtilityMethods::GetTimelineUtils(*m_ProfilingService);
915  ProfilingGuid inferenceGuid = m_ProfilingService->GetNextGuid();
916  if (timelineUtils)
917  {
918  // Add inference timeline trace if profiling is enabled.
919  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
920  timelineUtils->CreateTypedEntity(inferenceGuid, LabelsAndEventClasses::INFERENCE_GUID);
921  timelineUtils->CreateRelationship(ProfilingRelationshipType::RetentionLink,
922  networkGuid,
923  inferenceGuid,
924  LabelsAndEventClasses::EXECUTION_OF_GUID);
925  timelineUtils->RecordEvent(inferenceGuid, LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
926  }
927 
928  bool executionSucceeded = true;
929 
930  {
931  if (m_ProfilingService->IsProfilingEnabled())
932  {
933  m_ProfilingService->IncrementCounterValue(INFERENCES_RUN);
934  }
936  ARMNN_SCOPED_HEAP_PROFILING("Executing");
937  executionSucceeded = Execute(timelineUtils, inferenceGuid);
938  }
939 
940  if (timelineUtils)
941  {
942  // Add end of life of the inference timeline if profiling is enabled.
943  timelineUtils->RecordEvent(inferenceGuid, LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
944  timelineUtils->Commit();
945  }
946 
947  return executionSucceeded ? Status::Success : Status::Failure;
948 }
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.
#define ARMNN_LOG(severity)
Definition: Logging.hpp:205
#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name)
Definition: Profiling.hpp:220
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
#define ARMNN_SCOPED_HEAP_PROFILING(TAG)

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

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

Referenced by RuntimeImpl::Execute(), and LoadedNetwork::FreeWorkingMemory().

1633 {
1634  const Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
1635 
1636  if (inputTensors.size() + preImportedInputs.size() != graph.GetNumInputs())
1637  {
1638  if (preImportedInputs.empty())
1639  {
1640  throw InvalidArgumentException("LoadedNetwork::Execute: Number of inputs provided does not match network.");
1641  }
1642  else
1643  {
1644  throw InvalidArgumentException("LoadedNetwork::Execute: "
1645  "Number of inputs + preImportedInputs provided does not match network.");
1646  }
1647  }
1648 
1649  if (outputTensors.size() + preImportedOutputs.size() != graph.GetNumOutputs())
1650  {
1651  if (preImportedOutputs.empty())
1652  {
1653  throw InvalidArgumentException("LoadedNetwork::Execute: "
1654  "Number of outputs provided does not match network.");
1655  }
1656  else
1657  {
1658  throw InvalidArgumentException("LoadedNetwork::Execute: "
1659  "Number of outputs + preImportedOutputs provided does not match network.");
1660  }
1661  }
1662 
1663  WorkingMemHandle& workingMemHandle = dynamic_cast<WorkingMemHandle&>(iWorkingMemHandle);
1664  // Collect all the given LayerBindingIds and check them for duplicates and unknowns.
1665  std::vector<LayerBindingId>& bindingIds = workingMemHandle.GetBindingIdVector();
1666  unsigned int index = 0;
1667  for (auto pair : inputTensors)
1668  {
1669  bindingIds[index++] = pair.first;
1670  }
1671  for (ImportedInputId id : preImportedInputs)
1672  {
1673  bindingIds[index++] = ValidateImportedInputID(id);
1674  }
1675  for (auto pair : outputTensors)
1676  {
1677  bindingIds[index++] = pair.first;
1678  }
1679  for (ImportedOutputId id : preImportedOutputs)
1680  {
1681  bindingIds[index++] = ValidateImportedOutputID(id);
1682  }
1683 
1684  workingMemHandle.ValidateBindingIds();
1685 
1686  auto resetMemHandle = [&]()
1687  {
1688  for (ImportedInputId id: preImportedInputs)
1689  {
1690  const LayerBindingId layerBindingId = m_PreImportedInputHandles[id].m_LayerBindingId;
1691 
1692  auto inputHandle = workingMemHandle.GetInputHandle(layerBindingId);
1693  auto inputConnections = workingMemHandle.GetInputConnections(layerBindingId);
1694  for (auto it : inputConnections)
1695  {
1696  *it = inputHandle;
1697  }
1698  }
1699 
1700  for (ImportedOutputId id: preImportedOutputs)
1701  {
1702  const LayerBindingId layerBindingId = m_PreImportedOutputHandles[id].m_LayerBindingId;
1703 
1704  auto outputHandle = workingMemHandle.GetOutputHandle(layerBindingId);
1705  auto outputConnections = workingMemHandle.GetOutputConnection(layerBindingId);
1706 
1707  for (auto it : outputConnections)
1708  {
1709  *it = outputHandle;
1710  }
1711  }
1712  };
1713 
1714  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
1715  TimelineUtilityMethods::GetTimelineUtils(*m_ProfilingService);
1716  ProfilingGuid inferenceGuid = m_ProfilingService->GetNextGuid();
1717  if (timelineUtils)
1718  {
1719  // Add inference timeline trace if profiling is enabled.
1720  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
1721  timelineUtils->CreateTypedEntity(inferenceGuid,LabelsAndEventClasses::INFERENCE_GUID);
1722  timelineUtils->CreateRelationship(ProfilingRelationshipType::RetentionLink,
1723  networkGuid,
1724  inferenceGuid,
1725  LabelsAndEventClasses::EXECUTION_OF_GUID);
1726  timelineUtils->RecordEvent(inferenceGuid,LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
1727  }
1728 
1729  bool executionSucceeded = true;
1730 
1731  if (timelineUtils)
1732  {
1733  // Add end of life of the inference timeline if profiling is enabled.
1734  timelineUtils->RecordEvent(inferenceGuid,LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
1735  timelineUtils->Commit();
1736  }
1737 
1738  if (!workingMemHandle.IsAllocated())
1739  {
1740  workingMemHandle.Allocate();
1741  }
1742 
1743  {
1745  for (auto pair : inputTensors)
1746  {
1747  EnqueueInput(pair.second, workingMemHandle.GetInputHandle(pair.first));
1748  }
1749 
1750  // Swap in the pre-imported inputs if any
1751  for (ImportedInputId id : preImportedInputs)
1752  {
1753  const ImportedTensorHandlePin& importedInputPin = m_PreImportedInputHandles[id];
1754  const LayerBindingId layerBindingId = m_PreImportedInputHandles[id].m_LayerBindingId;
1755  const auto& preimportedHandle = importedInputPin.m_TensorHandle;
1756 
1757  auto inputConnections = workingMemHandle.GetInputConnections(layerBindingId);
1758  for (auto it : inputConnections)
1759  {
1760  *it = preimportedHandle.get();
1761  }
1762  }
1763  }
1764  {
1766  if (m_NetworkProperties.m_ExportEnabled)
1767  {
1768  for (auto pair: outputTensors)
1769  {
1770  ImportOutputTensor(pair.second, workingMemHandle.GetOutputHandle(pair.first));
1771  }
1772  }
1773 
1774  for (ImportedOutputId id : preImportedOutputs)
1775  {
1776  const ImportedTensorHandlePin& importedOutputPin = m_PreImportedOutputHandles[id];
1777  const LayerBindingId layerBindingId = m_PreImportedOutputHandles[id].m_LayerBindingId;
1778  const auto& preimportedHandle = importedOutputPin.m_TensorHandle;
1779 
1780  auto outputConnections = workingMemHandle.GetOutputConnection(layerBindingId);
1781 
1782  for (auto it : outputConnections)
1783  {
1784  *it = preimportedHandle.get();
1785  }
1786  }
1787  }
1788 
1789  auto Fail = [&](const std::exception& error)
1790  {
1791  ARMNN_LOG(error) << "An error occurred attempting to execute a workload: " << error.what();
1792  executionSucceeded = false;
1793  };
1794  ProfilingDynamicGuid workloadInferenceID(0);
1795 
1796  try
1797  {
1798  for (unsigned int i = 0; i < m_WorkloadQueue.size(); ++i)
1799  {
1800  auto& workload = m_WorkloadQueue[i];
1801  if (timelineUtils)
1802  {
1803  workloadInferenceID = timelineUtils->RecordWorkloadInferenceAndStartOfLifeEvent(workload->GetGuid(),
1804  inferenceGuid);
1805  }
1806  workload->ExecuteAsync(workingMemHandle.GetWorkingMemDescriptorAt(i));
1807 
1808  if (timelineUtils)
1809  {
1810  timelineUtils->RecordEndOfLifeEvent(workloadInferenceID);
1811  }
1812  }
1813  }
1814  catch (const RuntimeException& error)
1815  {
1816  resetMemHandle();
1817  Fail(error);
1818  }
1819  catch (const std::runtime_error& error)
1820  {
1821  resetMemHandle();
1822  Fail(error);
1823  }
1824  catch (...)
1825  {
1826  resetMemHandle();
1827  throw;
1828  }
1829 
1830  if (!m_NetworkProperties.m_ExportEnabled)
1831  {
1832  for (auto pair: outputTensors)
1833  {
1834  CopyToOutputTensor(pair.second, workingMemHandle.GetOutputHandle(pair.first));
1835  }
1836  }
1837  else
1838  {
1839  ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "SyncMemGeneric_Execute");
1840  workingMemHandle.MemSyncOutputs();
1841  }
1842 
1843  resetMemHandle();
1844 
1845  return executionSucceeded ? Status::Success : Status::Failure;
1846 }
unsigned int ImportedOutputId
Definition: Types.hpp:292
#define ARMNN_LOG(severity)
Definition: Logging.hpp:205
void CopyToOutputTensor(const Tensor &outputTensor, ITensorHandle *outputTensorHandle)
#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name)
Definition: Profiling.hpp:220
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:290
const bool m_ExportEnabled
Deprecated and will be removed in future release.
Definition: IRuntime.hpp:56
unsigned int ImportedInputId
Definition: Types.hpp:291

◆ FreeWorkingMemory()

void FreeWorkingMemory ( )

Definition at line 1141 of file LoadedNetwork.cpp.

References ARMNN_ASSERT_MSG, ARMNN_LOG, armnn::CheckFlag(), armnn::CopyTensorContentsGeneric(), armnn::error, LoadedNetwork::Execute(), ITensorHandle::GetImportFlags(), BaseTensor< MemoryType >::GetInfo(), BaseTensor< MemoryType >::GetMemoryArea(), ITensorHandle::Import(), and ITensorHandle::Map().

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

1142 {
1143 #if !defined(ARMNN_DISABLE_THREADS)
1144  std::lock_guard<std::mutex> lockGuard(m_WorkingMemMutex);
1145 #endif
1146 
1147  if (!m_IsWorkingMemAllocated)
1148  {
1149  return;
1150  }
1151 
1152  if (m_ExternalMemoryManager)
1153  {
1154  m_ExternalMemoryManager->Deallocate();
1155  }
1156 
1157  // Informs the memory managers to release memory in its respective memory group
1158  for (auto&& memoryManager : m_BackendMemoryMangers)
1159  {
1160  if (memoryManager)
1161  {
1162  memoryManager->Release();
1163  }
1164  }
1165  m_TensorHandleFactoryRegistry.ReleaseMemory();
1166  m_IsWorkingMemAllocated = false;
1167 }
void ReleaseMemory()
Release memory required for inference.

◆ GetInputTensorInfo()

TensorInfo GetInputTensorInfo ( LayerBindingId  layerId) const

Definition at line 606 of file LoadedNetwork.cpp.

References ARMNN_ASSERT_MSG.

Referenced by RuntimeImpl::GetInputTensorInfo().

607 {
608  for (auto&& inputLayer : m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetInputLayers())
609  {
610  ARMNN_ASSERT_MSG(inputLayer->GetNumOutputSlots() == 1, "Input layer should have exactly 1 output slot");
611  if (inputLayer->GetBindingId() == layerId)
612  {
613  return inputLayer->GetOutputSlot(0).GetTensorInfo();
614  }
615  }
616 
617  throw InvalidArgumentException(fmt::format("No input layer is associated with id {}", layerId));
618 }
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15

◆ GetNetworkGuid()

ProfilingGuid GetNetworkGuid ( )

Definition at line 601 of file LoadedNetwork.cpp.

602 {
603  return m_OptimizedNetwork->GetGuid();
604 }

◆ GetOutputTensorInfo()

TensorInfo GetOutputTensorInfo ( LayerBindingId  layerId) const

Definition at line 620 of file LoadedNetwork.cpp.

References ARMNN_ASSERT_MSG, CHECK_LOCATION, BackendId::Get(), Layer::GetBackendId(), Layer::GetNameStr(), armnn::IgnoreUnused(), armnn::info, and IWorkloadFactory::IsLayerSupported().

Referenced by RuntimeImpl::GetOutputTensorInfo().

621 {
622  for (auto&& outputLayer : m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetOutputLayers())
623  {
624  ARMNN_ASSERT_MSG(outputLayer->GetNumInputSlots() == 1, "Output layer should have exactly 1 input slot");
625  ARMNN_ASSERT_MSG(outputLayer->GetInputSlot(0).GetConnection(), "Input slot on Output layer must be connected");
626  if (outputLayer->GetBindingId() == layerId)
627  {
628  return outputLayer->GetInputSlot(0).GetConnection()->GetTensorInfo();
629  }
630  }
631 
632  throw InvalidArgumentException(fmt::format("No output layer is associated with id {}", layerId));
633 }
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15

◆ GetProfiler()

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

Definition at line 87 of file LoadedNetwork.hpp.

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

87 { return m_OptimizedNetwork->GetProfiler(); }

◆ ImportInputs()

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

Definition at line 1335 of file LoadedNetwork.cpp.

References ARMNN_ASSERT, Graph::InputLayersAccessor::begin(), ITensorHandle::CanBeImported(), armnn::CheckFlag(), ITensorHandleFactory::CreateTensorHandle(), Graph::InputLayersAccessor::end(), Layer::GetBackendId(), BindableLayer::GetBindingId(), ITensorHandle::GetImportFlags(), BaseTensor< MemoryType >::GetInfo(), Graph::GetInputLayers(), BaseTensor< MemoryType >::GetMemoryArea(), Layer::GetOutputSlots(), OutputSlot::GetTensorHandleFactoryId(), OutputSlot::GetTensorInfo(), Layer::GetType(), armnn::HasCapability(), ITensorHandle::Import(), armnn::Input, Graph::TopologicalSort(), and armnn::Undefined.

Referenced by RuntimeImpl::ImportInputs().

1337 {
1338  if (!m_NetworkProperties.m_AsyncEnabled)
1339  {
1340  // Cannot import if import is not enabled and forceImportMemorySource is undefined
1341  if (forceImportMemorySource == MemorySource::Undefined)
1342  {
1343  throw MemoryImportException("ImportInputs: Memory Import failed, NetworkProperties.m_ImportEnabled");
1344  }
1345  if (inputTensors.size() != m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetNumInputs())
1346  {
1347  throw MemoryImportException("ImportInputs: Force Import failed, incorrect number of tensors");
1348  }
1349 
1350  std::vector<ImportedInputId> importedInputs;
1351  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1352  unsigned int inputIndex = 0;
1353  for (const BindableLayer* inputLayer : graph.GetInputLayers())
1354  {
1355  auto outputTensorHandle = m_PreImportedInputHandles[inputIndex].m_TensorHandle.get();
1356 
1357  if (!outputTensorHandle)
1358  {
1359  inputIndex++;
1360  continue;
1361  }
1362 
1363  auto layerBindingId = inputLayer->GetBindingId();
1364  auto it = std::find_if(inputTensors.begin(), inputTensors.end(), [=](const auto& inputTensor)
1365  {
1366  return inputTensor.first == layerBindingId;
1367  });
1368 
1369  if (it == inputTensors.end())
1370  {
1371  inputIndex++;
1372  continue;
1373  }
1374 
1375  const auto& inputTensor = *it;
1376  std::unique_ptr<ITensorHandle> passThroughTensorHandle =
1377  std::make_unique<ConstPassthroughTensorHandle>(inputTensor.second.GetInfo(),
1378  inputTensor.second.GetMemoryArea());
1379 
1380  if (outputTensorHandle->CanBeImported(passThroughTensorHandle->Map(), forceImportMemorySource)
1381  && (outputTensorHandle->Import(passThroughTensorHandle->Map(), forceImportMemorySource)))
1382  {
1383  importedInputs.push_back(inputIndex);
1384  }
1385  passThroughTensorHandle->Unmap();
1386 
1387  inputIndex++;
1388  }
1389 
1390  return importedInputs;
1391  }
1392  else
1393  {
1394  // Import when the import of network properties is enabled
1395  std::vector<ImportedInputId> importedInputs;
1396  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1397 
1398  for (auto inputTensor : inputTensors)
1399  {
1400  auto layerBindingId = inputTensor.first;
1401  auto it = std::find_if(graph.GetInputLayers().begin(), graph.GetInputLayers().end(), [=](auto* layer)
1402  {
1403  return layer->GetBindingId() == layerBindingId;
1404  });
1405 
1406  if (it == graph.GetInputLayers().end())
1407  {
1408  throw MemoryImportException(fmt::format(
1409  "ImportInputs: Memory Import failed, unknown LayerBindingId: {}", layerBindingId));
1410  }
1411 
1412  const Layer* layer = *it;
1413  if (layer->GetType() != LayerType::Input)
1414  {
1415  throw InvalidArgumentException("ImportInputs: given layer not an InputLayer");
1416  }
1417 
1418  auto& backend = m_Backends.at(layer->GetBackendId());
1419  if (!HasCapability(BackendOptions::BackendOption{"PreImportIOTensors", true}, backend->GetCapabilities()))
1420  {
1421  std::string er = backend->GetId();
1422  er += " does not have PreImportIOTensors capability";
1423  throw BackendCapabilityException(er);
1424  }
1425 
1426  const OutputSlot& outputSlot = layer->GetOutputSlots()[0];
1427 
1428  ITensorHandleFactory::FactoryId factoryId = outputSlot.GetTensorHandleFactoryId();
1429  const TensorInfo& tensorInfo = outputSlot.GetTensorInfo();
1430 
1431  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1432  ARMNN_ASSERT(handleFactory);
1433 
1434  ImportedTensorHandlePin importedTensorHandlePin{layerBindingId,
1435  handleFactory->CreateTensorHandle(tensorInfo, false)};
1436 
1437  ITensorHandle* tensorHandle = importedTensorHandlePin.m_TensorHandle.get();
1438 
1439  if (!CheckFlag(tensorHandle->GetImportFlags(), m_NetworkProperties.m_InputSource))
1440  {
1441  throw MemoryImportException(
1442  fmt::format("ImportInputs: Memory Import failed, backend: "
1443  "{} does not support importing from source {}"
1444  , factoryId, m_NetworkProperties.m_InputSource));
1445  }
1446 
1447  std::unique_ptr<ITensorHandle> passThroughTensorHandle =
1448  std::make_unique<ConstPassthroughTensorHandle>(inputTensor.second.GetInfo(),
1449  inputTensor.second.GetMemoryArea());
1450 
1451  if (tensorHandle->Import(passThroughTensorHandle->Map(), m_NetworkProperties.m_InputSource))
1452  {
1453  importedInputs.push_back(m_CurImportedInputId++);
1454  passThroughTensorHandle->Unmap();
1455  }
1456  else
1457  {
1458  passThroughTensorHandle->Unmap();
1459  throw MemoryImportException("ImportInputs: Memory Import failed");
1460  }
1461 
1462  m_PreImportedInputHandles.push_back(std::move(importedTensorHandlePin));
1463  }
1464  return importedInputs;
1465  }
1466 }
bool HasCapability(const std::string &name, const BackendCapabilities &capabilities)
Convenience function to check if a capability exists in a BackendCapabilites struct.
const MemorySource m_InputSource
Definition: IRuntime.hpp:64
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
Find a TensorHandleFactory by Id Returns nullptr if not found.
bool CheckFlag(MemorySourceFlags flags, MemorySource source)

◆ ImportOutputs()

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

Definition at line 1468 of file LoadedNetwork.cpp.

References ARMNN_ASSERT, Graph::OutputLayersAccessor::begin(), ITensorHandle::CanBeImported(), armnn::CheckFlag(), ITensorHandleFactory::CreateTensorHandle(), Graph::OutputLayersAccessor::end(), Layer::GetBackendId(), BindableLayer::GetBindingId(), InputSlot::GetConnectedOutputSlot(), ITensorHandle::GetImportFlags(), Layer::GetInputSlots(), BaseTensor< MemoryType >::GetMemoryArea(), Graph::GetOutputLayers(), OutputSlot::GetTensorHandleFactoryId(), OutputSlot::GetTensorInfo(), Layer::GetType(), armnn::HasCapability(), ITensorHandle::Import(), armnn::Output, Graph::TopologicalSort(), and armnn::Undefined.

Referenced by RuntimeImpl::ImportOutputs().

1470 {
1471  if (!m_NetworkProperties.m_AsyncEnabled)
1472  {
1473  // Cannot import if import is not enabled and forceImportMemorySource is undefined
1474  if (forceImportMemorySource == MemorySource::Undefined)
1475  {
1476  throw MemoryImportException("ImportOutputs: Memory Import failed, NetworkProperties.m_ImportEnabled");
1477  }
1478  // If forceImportMemorySource is defined, try import if memory is aligned
1479  if (outputTensors.size() != m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetNumOutputs())
1480  {
1481  throw MemoryImportException("ImportOutputs: Force Import failed, incorrect number of tensors");
1482  }
1483  std::vector<ImportedOutputId> importedOutputs;
1484  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1485 
1486  unsigned int outputIndex = 0;
1487  for (const BindableLayer* const outputLayer : graph.GetOutputLayers())
1488  {
1489  auto inputTensorHandle = m_PreImportedOutputHandles[outputIndex].m_TensorHandle.get();
1490 
1491  if (!inputTensorHandle)
1492  {
1493  outputIndex++;
1494  continue;
1495  }
1496 
1497  auto layerBindingId = outputLayer->GetBindingId();
1498  auto it = std::find_if(outputTensors.begin(), outputTensors.end(), [=] (const auto& outputTensor)
1499  {
1500  return outputTensor.first == layerBindingId;
1501  });
1502 
1503  if (it == outputTensors.end())
1504  {
1505  outputIndex++;
1506  continue;
1507  }
1508 
1509  const auto outputTensor = *it;
1510  // Check if the output memory can be imported
1511  if (inputTensorHandle->CanBeImported(outputTensor.second.GetMemoryArea(), forceImportMemorySource)
1512  && inputTensorHandle->Import(outputTensor.second.GetMemoryArea(), forceImportMemorySource))
1513  {
1514  importedOutputs.push_back(outputIndex);
1515  }
1516  outputIndex++;
1517  }
1518  return importedOutputs;
1519  }
1520 
1521  std::vector<ImportedOutputId> importedOutputs;
1522  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1523 
1524  for (const auto& outputTensor : outputTensors)
1525  {
1526  auto layerBindingId = outputTensor.first;
1527  auto it = std::find_if(graph.GetOutputLayers().begin(), graph.GetOutputLayers().end(), [=](auto* layer)
1528  {
1529  return layer->GetBindingId() == layerBindingId;
1530  });
1531 
1532  if (it == graph.GetOutputLayers().end())
1533  {
1534  throw MemoryImportException(fmt::format("ImportOutputs: Memory Import failed, unknown LayerBindingId: {}",
1535  layerBindingId));
1536  }
1537 
1538  const Layer* layer = *it;
1539  if (layer->GetType() != LayerType::Output)
1540  {
1541  throw InvalidArgumentException("ImportOutputs: given layer not an OutputLayer");
1542  }
1543 
1544  auto& backend = m_Backends.at(layer->GetBackendId());
1545  if (!HasCapability(BackendOptions::BackendOption{"PreImportIOTensors", true}, backend->GetCapabilities()))
1546  {
1547  std::string er = backend->GetId();
1548  er += " does not have PreImportIOTensors capability";
1549  throw BackendCapabilityException(er);
1550  }
1551 
1552  const InputSlot& inputSlot = layer->GetInputSlots()[0];
1553  ITensorHandleFactory::FactoryId factoryId = inputSlot.GetConnectedOutputSlot()->GetTensorHandleFactoryId();
1554  const TensorInfo& tensorInfo = inputSlot.GetConnectedOutputSlot()->GetTensorInfo();
1555 
1556  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1557  ARMNN_ASSERT(handleFactory);
1558 
1559  ImportedTensorHandlePin importedTensorHandlePin{layerBindingId,
1560  handleFactory->CreateTensorHandle(tensorInfo, false)};
1561 
1562  ITensorHandle* tensorHandle = importedTensorHandlePin.m_TensorHandle.get();
1563 
1564  if (!CheckFlag(tensorHandle->GetImportFlags(), m_NetworkProperties.m_OutputSource))
1565  {
1566  throw MemoryImportException(fmt::format("ImportInputs: Memory Import failed, backend: "
1567  "{} does not support importing from source {}"
1568  , factoryId, m_NetworkProperties.m_OutputSource));
1569  }
1570 
1571  if (tensorHandle->Import(outputTensor.second.GetMemoryArea(), m_NetworkProperties.m_OutputSource))
1572  {
1573  importedOutputs.push_back(m_CurImportedOutputId++);
1574  }
1575  else
1576  {
1577  throw MemoryImportException("ImportInputs: Memory Import failed");
1578  }
1579 
1580  m_PreImportedOutputHandles.push_back(std::move(importedTensorHandlePin));
1581  }
1582 
1583  return importedOutputs;
1584 }
bool HasCapability(const std::string &name, const BackendCapabilities &capabilities)
Convenience function to check if a capability exists in a BackendCapabilites struct.
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
Find a TensorHandleFactory by Id Returns nullptr if not found.
const MemorySource m_OutputSource
Definition: IRuntime.hpp:65
bool CheckFlag(MemorySourceFlags flags, MemorySource source)

◆ IsAsyncEnabled()

bool IsAsyncEnabled ( )
inline

Definition at line 95 of file LoadedNetwork.hpp.

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

96  {
97  return m_NetworkProperties.m_AsyncEnabled;
98  }

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

References ITensorHandle::Allocate(), ARMNN_ASSERT, ARMNN_LOG, ARMNN_SCOPED_PROFILING_EVENT, armnn::BackendRegistryInstance(), armnn::Constant, IBackendInternal::CreateMemoryManager(), ITensorHandleFactory::CreateTensorHandle(), IBackendInternal::CreateWorkloadFactory(), armnn::error, IBackendInternal::GetCapabilities(), BackendRegistry::GetFactory(), IBackend::GetId(), ProfilerManager::GetInstance(), BackendRegistry::GetMemoryOptimizerStrategies(), Graph::GetNumInputs(), Graph::GetNumOutputs(), armnn::HasCapability(), armnn::Input, ITensorHandleFactory::LegacyFactoryId, INetworkProperties::m_AsyncEnabled, INetworkProperties::m_OutputNetworkDetailsMethod, WorkingMemDescriptor::m_Outputs, INetworkProperties::m_ProfilingEnabled, armnn::MemImport, armnn::numeric_cast(), armnn::Output, ProfilerManager::RegisterProfiler(), IBackendInternal::SupportsTensorAllocatorAPI(), Graph::TopologicalSort(), and armnn::Undefined.

Referenced by RuntimeImpl::LoadNetwork().

91 {
92  std::unique_ptr<LoadedNetwork> loadedNetwork;
93 
94  auto Fail = [&](const std::exception& error) -> std::unique_ptr<LoadedNetwork>
95  {
96  errorMessage = ToErrorMessage("An error occurred when preparing the network workloads: ", error);
97  ARMNN_LOG(error) << errorMessage;
98 
99  return std::unique_ptr<LoadedNetwork>();
100  };
101 
102  try
103  {
104  loadedNetwork.reset(new LoadedNetwork(std::move(net), networkProperties, profilingService));
105  }
106  catch (const armnn::RuntimeException& error)
107  {
108  return Fail(error);
109  }
110  catch (const armnn::Exception& error)
111  {
112  return Fail(error);
113  }
114  catch (const std::runtime_error& error)
115  {
116  return Fail(error);
117  }
118 
119  return loadedNetwork;
120 }
#define ARMNN_LOG(severity)
Definition: Logging.hpp:205
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46

◆ RegisterDebugCallback()

◆ SendNetworkStructure()

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

Definition at line 563 of file LoadedNetwork.cpp.

References ARMNN_SCOPED_PROFILING_EVENT, armnn::Input, armnn::Output, Graph::TopologicalSort(), and armnn::Undefined.

564 {
565  ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "LoadNetwork_SendNetworkStructure");
566  Graph& order = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
567  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
568 
569  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
570  TimelineUtilityMethods::GetTimelineUtils(profilingService);
571 
572  timelineUtils->CreateTypedEntity(networkGuid, LabelsAndEventClasses::NETWORK_GUID);
573 
574  for (auto&& layer : order)
575  {
576  // Add layer to the post-optimisation network structure
577  AddLayerStructure(timelineUtils, *layer, networkGuid);
578  switch (layer->GetType())
579  {
580  case LayerType::Input:
581  case LayerType::Output:
582  {
583  // Inputs and outputs are treated in a special way - see EnqueueInput() and EnqueueOutput().
584  break;
585  }
586  default:
587  {
588  for (auto& workload : m_WorkloadQueue)
589  {
590  // Add workload to the post-optimisation network structure
591  AddWorkloadStructure(timelineUtils, workload, *layer);
592  }
593  break;
594  }
595  }
596  }
597  // Commit to send the post-optimisation network structure
598  timelineUtils->Commit();
599 }
#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name)
Definition: Profiling.hpp:220

The documentation for this class was generated from the following files: