ArmNN
 22.02
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 ()
 
bool IsAsyncEnabled ()
 
profiling::ProfilingGuid GetNetworkGuid ()
 

Static Public Member Functions

static std::unique_ptr< LoadedNetworkMakeLoadedNetwork (std::unique_ptr< IOptimizedNetwork > net, std::string &errorMessage, const INetworkProperties &networkProperties, profiling::ProfilingService &profilingService)
 

Detailed Description

Definition at line 41 of file LoadedNetwork.hpp.

Member Typedef Documentation

◆ WorkloadQueue

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

Definition at line 44 of file LoadedNetwork.hpp.

Constructor & Destructor Documentation

◆ ~LoadedNetwork()

~LoadedNetwork ( )
inline

Definition at line 46 of file LoadedNetwork.hpp.

47  {
49  }

Member Function Documentation

◆ ClearImportedInputs()

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

Definition at line 1557 of file LoadedNetwork.cpp.

Referenced by RuntimeImpl::ClearImportedInputs().

1558 {
1559  for (auto id : inputIds)
1560  {
1561  if (id > m_PreImportedInputHandles.size())
1562  {
1563  throw InvalidArgumentException(fmt::format("ClearImportedInputs::Unknown ImportedInputId: {}", id));
1564  }
1565 
1566  auto& importedTensorHandle = m_PreImportedInputHandles[id].m_TensorHandle;
1567  if (!importedTensorHandle)
1568  {
1569  throw InvalidArgumentException(
1570  fmt::format("ClearImportedInputs::ImportedInput with id: {} has already been deleted", id));
1571  }
1572  // Call Unimport then destroy the tensorHandle
1573  importedTensorHandle->Unimport();
1574  importedTensorHandle = {};
1575  }
1576 }

◆ ClearImportedOutputs()

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

Definition at line 1578 of file LoadedNetwork.cpp.

Referenced by RuntimeImpl::ClearImportedOutputs().

1579 {
1580  for (auto id : outputIds)
1581  {
1582  if (id > m_PreImportedOutputHandles.size())
1583  {
1584  throw InvalidArgumentException(fmt::format("ClearImportedOutputs::Unknown ImportedOutputId: {}", id));
1585  }
1586 
1587  auto& importedTensorHandle = m_PreImportedOutputHandles[id].m_TensorHandle;
1588  if (!importedTensorHandle)
1589  {
1590  throw InvalidArgumentException(
1591  fmt::format("ClearImportedOutputs::ImportedOutput with id: {} has already been deleted", id));
1592  }
1593  // Call Unimport then destroy the tensorHandle
1594  importedTensorHandle->Unimport();
1595  importedTensorHandle = {};
1596  }
1597 }

◆ 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 1821 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().

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

References ARMNN_ASSERT_MSG, ARMNN_LOG, ARMNN_SCOPED_HEAP_PROFILING, ARMNN_SCOPED_PROFILING_EVENT, armnn::CheckFlag(), armnn::Failure, OutputHandler::GetData(), ITensorHandle::GetImportFlags(), Graph::GetInputLayers(), Layer::GetInputSlots(), Graph::GetNumInputs(), Layer::GetNumInputSlots(), Graph::GetNumLayers(), Graph::GetNumOutputs(), Layer::GetNumOutputSlots(), Layer::GetOutputHandler(), Graph::GetOutputLayers(), TimelineUtilityMethods::GetTimelineUtils(), Layer::GetType(), armnn::IgnoreUnused(), ITensorHandle::Import(), armnn::info, armnn::Input, QueueDescriptor::m_Inputs, WorkloadInfo::m_InputTensorInfos, QueueDescriptor::m_Outputs, WorkloadInfo::m_OutputTensorInfos, ITensorHandle::Map(), armnn::Output, armnn::Success, armnn::Undefined, ITensorHandle::Unmap(), and armnn::warning.

Referenced by RuntimeImpl::EnqueueWorkload().

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

◆ 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 1599 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(), TimelineUtilityMethods::GetTimelineUtils(), WorkingMemHandle::GetWorkingMemDescriptorAt(), WorkingMemHandle::IsAllocated(), WorkingMemHandle::MemSyncOutputs(), armnn::profiling::RetentionLink, armnn::Success, armnn::Undefined, and WorkingMemHandle::ValidateBindingIds().

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

1604 {
1605  const Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph();
1606 
1607  if (inputTensors.size() + preImportedInputs.size() != graph.GetNumInputs())
1608  {
1609  if (preImportedInputs.empty())
1610  {
1611  throw InvalidArgumentException("LoadedNetwork::Execute: Number of inputs provided does not match network.");
1612  }
1613  else
1614  {
1615  throw InvalidArgumentException("LoadedNetwork::Execute: "
1616  "Number of inputs + preImportedInputs provided does not match network.");
1617  }
1618  }
1619 
1620  if (outputTensors.size() + preImportedOutputs.size() != graph.GetNumOutputs())
1621  {
1622  if (preImportedOutputs.empty())
1623  {
1624  throw InvalidArgumentException("LoadedNetwork::Execute: "
1625  "Number of outputs provided does not match network.");
1626  }
1627  else
1628  {
1629  throw InvalidArgumentException("LoadedNetwork::Execute: "
1630  "Number of outputs + preImportedOutputs provided does not match network.");
1631  }
1632  }
1633 
1634  WorkingMemHandle& workingMemHandle = dynamic_cast<WorkingMemHandle&>(iWorkingMemHandle);
1635  // Collect all the given LayerBindingIds and check them for duplicates and unknowns.
1636  std::vector<LayerBindingId>& bindingIds = workingMemHandle.GetBindingIdVector();
1637  unsigned int index = 0;
1638  for (auto pair : inputTensors)
1639  {
1640  bindingIds[index++] = pair.first;
1641  }
1642  for (ImportedInputId id : preImportedInputs)
1643  {
1644  bindingIds[index++] = ValidateImportedInputID(id);
1645  }
1646  for (auto pair : outputTensors)
1647  {
1648  bindingIds[index++] = pair.first;
1649  }
1650  for (ImportedOutputId id : preImportedOutputs)
1651  {
1652  bindingIds[index++] = ValidateImportedOutputID(id);
1653  }
1654 
1655  workingMemHandle.ValidateBindingIds();
1656 
1657  auto resetMemHandle = [&]()
1658  {
1659  for (ImportedInputId id: preImportedInputs)
1660  {
1661  const LayerBindingId layerBindingId = m_PreImportedInputHandles[id].m_LayerBindingId;
1662 
1663  auto inputHandle = workingMemHandle.GetInputHandle(layerBindingId);
1664  auto inputConnections = workingMemHandle.GetInputConnections(layerBindingId);
1665  for (auto it : inputConnections)
1666  {
1667  *it = inputHandle;
1668  }
1669  }
1670 
1671  for (ImportedOutputId id: preImportedOutputs)
1672  {
1673  const LayerBindingId layerBindingId = m_PreImportedOutputHandles[id].m_LayerBindingId;
1674 
1675  auto outputHandle = workingMemHandle.GetOutputHandle(layerBindingId);
1676  auto outputConnections = workingMemHandle.GetOutputConnection(layerBindingId);
1677 
1678  for (auto it : outputConnections)
1679  {
1680  *it = outputHandle;
1681  }
1682  }
1683  };
1684 
1685  std::unique_ptr<profiling::TimelineUtilityMethods> timelineUtils =
1687  profiling::ProfilingGuid inferenceGuid = m_ProfilingService.GetNextGuid();
1688  if (timelineUtils)
1689  {
1690  // Add inference timeline trace if profiling is enabled.
1691  profiling::ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
1692  timelineUtils->CreateTypedEntity(inferenceGuid, profiling::LabelsAndEventClasses::INFERENCE_GUID);
1693  timelineUtils->CreateRelationship(profiling::ProfilingRelationshipType::RetentionLink,
1694  networkGuid,
1695  inferenceGuid,
1696  profiling::LabelsAndEventClasses::EXECUTION_OF_GUID);
1697  timelineUtils->RecordEvent(inferenceGuid, profiling::LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
1698  }
1699 
1700  bool executionSucceeded = true;
1701 
1702  if (timelineUtils)
1703  {
1704  // Add end of life of the inference timeline if profiling is enabled.
1705  timelineUtils->RecordEvent(inferenceGuid, profiling::LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
1706  timelineUtils->Commit();
1707  }
1708 
1709  if (!workingMemHandle.IsAllocated())
1710  {
1711  workingMemHandle.Allocate();
1712  }
1713 
1714  {
1716  for (auto pair : inputTensors)
1717  {
1718  EnqueueInput(pair.second, workingMemHandle.GetInputHandle(pair.first));
1719  }
1720 
1721  // Swap in the pre-imported inputs if any
1722  for (ImportedInputId id : preImportedInputs)
1723  {
1724  const ImportedTensorHandlePin& importedInputPin = m_PreImportedInputHandles[id];
1725  const LayerBindingId layerBindingId = m_PreImportedInputHandles[id].m_LayerBindingId;
1726  const auto& preimportedHandle = importedInputPin.m_TensorHandle;
1727 
1728  auto inputConnections = workingMemHandle.GetInputConnections(layerBindingId);
1729  for (auto it : inputConnections)
1730  {
1731  *it = preimportedHandle.get();
1732  }
1733  }
1734  }
1735  {
1737  if (m_NetworkProperties.m_ExportEnabled)
1738  {
1739  for (auto pair: outputTensors)
1740  {
1741  ImportOutputTensor(pair.second, workingMemHandle.GetOutputHandle(pair.first));
1742  }
1743  }
1744 
1745  for (ImportedOutputId id : preImportedOutputs)
1746  {
1747  const ImportedTensorHandlePin& importedOutputPin = m_PreImportedOutputHandles[id];
1748  const LayerBindingId layerBindingId = m_PreImportedOutputHandles[id].m_LayerBindingId;
1749  const auto& preimportedHandle = importedOutputPin.m_TensorHandle;
1750 
1751  auto outputConnections = workingMemHandle.GetOutputConnection(layerBindingId);
1752 
1753  for (auto it : outputConnections)
1754  {
1755  *it = preimportedHandle.get();
1756  }
1757  }
1758  }
1759 
1760  auto Fail = [&](const std::exception& error)
1761  {
1762  ARMNN_LOG(error) << "An error occurred attempting to execute a workload: " << error.what();
1763  executionSucceeded = false;
1764  };
1765  profiling::ProfilingDynamicGuid workloadInferenceID(0);
1766 
1767  try
1768  {
1769  for (unsigned int i = 0; i < m_WorkloadQueue.size(); ++i)
1770  {
1771  auto& workload = m_WorkloadQueue[i];
1772  if (timelineUtils)
1773  {
1774  workloadInferenceID = timelineUtils->RecordWorkloadInferenceAndStartOfLifeEvent(workload->GetGuid(),
1775  inferenceGuid);
1776  }
1777  workload->ExecuteAsync(workingMemHandle.GetWorkingMemDescriptorAt(i));
1778 
1779  if (timelineUtils)
1780  {
1781  timelineUtils->RecordEndOfLifeEvent(workloadInferenceID);
1782  }
1783  }
1784  }
1785  catch (const RuntimeException& error)
1786  {
1787  resetMemHandle();
1788  Fail(error);
1789  }
1790  catch (const std::runtime_error& error)
1791  {
1792  resetMemHandle();
1793  Fail(error);
1794  }
1795  catch (...)
1796  {
1797  resetMemHandle();
1798  throw;
1799  }
1800 
1801  if (!m_NetworkProperties.m_ExportEnabled)
1802  {
1803  for (auto pair: outputTensors)
1804  {
1805  CopyToOutputTensor(pair.second, workingMemHandle.GetOutputHandle(pair.first));
1806  }
1807  }
1808  else
1809  {
1810  ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "SyncMemGeneric_Execute");
1811  workingMemHandle.MemSyncOutputs();
1812  }
1813 
1814  resetMemHandle();
1815 
1816  return executionSucceeded ? Status::Success : Status::Failure;
1817 }
static std::unique_ptr< TimelineUtilityMethods > GetTimelineUtils(ProfilingService &profilingService)
unsigned int ImportedOutputId
Definition: Types.hpp:279
#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:277
const bool m_ExportEnabled
Deprecated and will be removed in future release.
Definition: IRuntime.hpp:54
unsigned int ImportedInputId
Definition: Types.hpp:278
static ProfilingDynamicGuid GetNextGuid()

◆ FreeWorkingMemory()

void FreeWorkingMemory ( )

Definition at line 1118 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().

1119 {
1120  std::lock_guard<std::mutex> lockGuard(m_WorkingMemMutex);
1121 
1122  if (!m_IsWorkingMemAllocated)
1123  {
1124  return;
1125  }
1126 
1127  if (m_ExternalMemoryManager)
1128  {
1129  m_ExternalMemoryManager->Deallocate();
1130  }
1131 
1132  // Informs the memory managers to release memory in its respective memory group
1133  for (auto&& memoryManager : m_BackendMemoryMangers)
1134  {
1135  if (memoryManager)
1136  {
1137  memoryManager->Release();
1138  }
1139  }
1140  m_TensorHandleFactoryRegistry.ReleaseMemory();
1141  m_IsWorkingMemAllocated = false;
1142 }
void ReleaseMemory()
Release memory required for inference.

◆ GetInputTensorInfo()

TensorInfo GetInputTensorInfo ( LayerBindingId  layerId) const

Definition at line 588 of file LoadedNetwork.cpp.

References ARMNN_ASSERT_MSG.

Referenced by RuntimeImpl::GetInputTensorInfo().

589 {
590  for (auto&& inputLayer : m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetInputLayers())
591  {
592  ARMNN_ASSERT_MSG(inputLayer->GetNumOutputSlots() == 1, "Input layer should have exactly 1 output slot");
593  if (inputLayer->GetBindingId() == layerId)
594  {
595  return inputLayer->GetOutputSlot(0).GetTensorInfo();
596  }
597  }
598 
599  throw InvalidArgumentException(fmt::format("No input layer is associated with id {}", layerId));
600 }
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15

◆ GetNetworkGuid()

profiling::ProfilingGuid GetNetworkGuid ( )

Definition at line 583 of file LoadedNetwork.cpp.

584 {
585  return m_OptimizedNetwork->GetGuid();
586 }

◆ GetOutputTensorInfo()

TensorInfo GetOutputTensorInfo ( LayerBindingId  layerId) const

Definition at line 602 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().

603 {
604  for (auto&& outputLayer : m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetOutputLayers())
605  {
606  ARMNN_ASSERT_MSG(outputLayer->GetNumInputSlots() == 1, "Output layer should have exactly 1 input slot");
607  ARMNN_ASSERT_MSG(outputLayer->GetInputSlot(0).GetConnection(), "Input slot on Output layer must be connected");
608  if (outputLayer->GetBindingId() == layerId)
609  {
610  return outputLayer->GetInputSlot(0).GetConnection()->GetTensorInfo();
611  }
612  }
613 
614  throw InvalidArgumentException(fmt::format("No output layer is associated with id {}", layerId));
615 }
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15

◆ GetProfiler()

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

Definition at line 86 of file LoadedNetwork.hpp.

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

86 { return m_OptimizedNetwork->GetProfiler(); }

◆ ImportInputs()

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

Definition at line 1306 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().

1308 {
1309  if (!m_NetworkProperties.m_AsyncEnabled)
1310  {
1311  // Cannot import if import is not enabled and forceImportMemorySource is undefined
1312  if (forceImportMemorySource == MemorySource::Undefined)
1313  {
1314  throw MemoryImportException("ImportInputs: Memory Import failed, NetworkProperties.m_ImportEnabled");
1315  }
1316  if (inputTensors.size() != m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetNumInputs())
1317  {
1318  throw MemoryImportException("ImportInputs: Force Import failed, incorrect number of tensors");
1319  }
1320 
1321  std::vector<ImportedInputId> importedInputs;
1322  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1323  unsigned int inputIndex = 0;
1324  for (const BindableLayer* inputLayer : graph.GetInputLayers())
1325  {
1326  auto outputTensorHandle = m_PreImportedInputHandles[inputIndex].m_TensorHandle.get();
1327 
1328  if (!outputTensorHandle)
1329  {
1330  inputIndex++;
1331  continue;
1332  }
1333 
1334  auto layerBindingId = inputLayer->GetBindingId();
1335  auto it = std::find_if(inputTensors.begin(), inputTensors.end(), [=](const auto& inputTensor)
1336  {
1337  return inputTensor.first == layerBindingId;
1338  });
1339 
1340  if (it == inputTensors.end())
1341  {
1342  inputIndex++;
1343  continue;
1344  }
1345 
1346  const auto& inputTensor = *it;
1347  std::unique_ptr<ITensorHandle> passThroughTensorHandle =
1348  std::make_unique<ConstPassthroughTensorHandle>(inputTensor.second.GetInfo(),
1349  inputTensor.second.GetMemoryArea());
1350 
1351  if (outputTensorHandle->CanBeImported(passThroughTensorHandle->Map(), forceImportMemorySource)
1352  && (outputTensorHandle->Import(passThroughTensorHandle->Map(), forceImportMemorySource)))
1353  {
1354  importedInputs.push_back(inputIndex);
1355  }
1356  passThroughTensorHandle->Unmap();
1357 
1358  inputIndex++;
1359  }
1360 
1361  return importedInputs;
1362  }
1363  else
1364  {
1365  // Import when the import of network properties is enabled
1366  std::vector<ImportedInputId> importedInputs;
1367  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1368 
1369  for (auto inputTensor : inputTensors)
1370  {
1371  auto layerBindingId = inputTensor.first;
1372  auto it = std::find_if(graph.GetInputLayers().begin(), graph.GetInputLayers().end(), [=](auto* layer)
1373  {
1374  return layer->GetBindingId() == layerBindingId;
1375  });
1376 
1377  if (it == graph.GetInputLayers().end())
1378  {
1379  throw MemoryImportException(fmt::format(
1380  "ImportInputs: Memory Import failed, unknown LayerBindingId: {}", layerBindingId));
1381  }
1382 
1383  const Layer* layer = *it;
1384  if (layer->GetType() != LayerType::Input)
1385  {
1386  throw InvalidArgumentException("ImportInputs: given layer not an InputLayer");
1387  }
1388 
1389  auto& backend = m_Backends.at(layer->GetBackendId());
1390  if (!HasCapability(BackendOptions::BackendOption{"PreImportIOTensors", true}, backend->GetCapabilities()))
1391  {
1392  std::string er = backend->GetId();
1393  er += " does not have PreImportIOTensors capability";
1394  throw BackendCapabilityException(er);
1395  }
1396 
1397  const OutputSlot& outputSlot = layer->GetOutputSlots()[0];
1398 
1399  ITensorHandleFactory::FactoryId factoryId = outputSlot.GetTensorHandleFactoryId();
1400  const TensorInfo& tensorInfo = outputSlot.GetTensorInfo();
1401 
1402  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1403  ARMNN_ASSERT(handleFactory);
1404 
1405  ImportedTensorHandlePin importedTensorHandlePin{layerBindingId,
1406  handleFactory->CreateTensorHandle(tensorInfo, false)};
1407 
1408  ITensorHandle* tensorHandle = importedTensorHandlePin.m_TensorHandle.get();
1409 
1410  if (!CheckFlag(tensorHandle->GetImportFlags(), m_NetworkProperties.m_InputSource))
1411  {
1412  throw MemoryImportException(
1413  fmt::format("ImportInputs: Memory Import failed, backend: "
1414  "{} does not support importing from source {}"
1415  , factoryId, m_NetworkProperties.m_InputSource));
1416  }
1417 
1418  std::unique_ptr<ITensorHandle> passThroughTensorHandle =
1419  std::make_unique<ConstPassthroughTensorHandle>(inputTensor.second.GetInfo(),
1420  inputTensor.second.GetMemoryArea());
1421 
1422  if (tensorHandle->Import(passThroughTensorHandle->Map(), m_NetworkProperties.m_InputSource))
1423  {
1424  importedInputs.push_back(m_CurImportedInputId++);
1425  passThroughTensorHandle->Unmap();
1426  }
1427  else
1428  {
1429  passThroughTensorHandle->Unmap();
1430  throw MemoryImportException("ImportInputs: Memory Import failed");
1431  }
1432 
1433  m_PreImportedInputHandles.push_back(std::move(importedTensorHandlePin));
1434  }
1435  return importedInputs;
1436  }
1437 }
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:62
#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 1439 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().

1441 {
1442  if (!m_NetworkProperties.m_AsyncEnabled)
1443  {
1444  // Cannot import if import is not enabled and forceImportMemorySource is undefined
1445  if (forceImportMemorySource == MemorySource::Undefined)
1446  {
1447  throw MemoryImportException("ImportOutputs: Memory Import failed, NetworkProperties.m_ImportEnabled");
1448  }
1449  // If forceImportMemorySource is defined, try import if memory is aligned
1450  if (outputTensors.size() != m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().GetNumOutputs())
1451  {
1452  throw MemoryImportException("ImportOutputs: Force Import failed, incorrect number of tensors");
1453  }
1454  std::vector<ImportedInputId> importedOutputs;
1455  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1456 
1457  unsigned int outputIndex = 0;
1458  for (const BindableLayer* const outputLayer : graph.GetOutputLayers())
1459  {
1460  auto inputTensorHandle = m_PreImportedOutputHandles[outputIndex].m_TensorHandle.get();
1461 
1462  if (!inputTensorHandle)
1463  {
1464  outputIndex++;
1465  continue;
1466  }
1467 
1468  auto layerBindingId = outputLayer->GetBindingId();
1469  auto it = std::find_if(outputTensors.begin(), outputTensors.end(), [=] (const auto& outputTensor)
1470  {
1471  return outputTensor.first == layerBindingId;
1472  });
1473 
1474  if (it == outputTensors.end())
1475  {
1476  outputIndex++;
1477  continue;
1478  }
1479 
1480  const auto outputTensor = *it;
1481  // Check if the output memory can be imported
1482  if (inputTensorHandle->CanBeImported(outputTensor.second.GetMemoryArea(), forceImportMemorySource)
1483  && inputTensorHandle->Import(outputTensor.second.GetMemoryArea(), forceImportMemorySource))
1484  {
1485  importedOutputs.push_back(outputIndex);
1486  }
1487  outputIndex++;
1488  }
1489  return importedOutputs;
1490  }
1491 
1492  std::vector<ImportedOutputId> importedOutputs;
1493  Graph& graph = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
1494 
1495  for (const auto& outputTensor : outputTensors)
1496  {
1497  auto layerBindingId = outputTensor.first;
1498  auto it = std::find_if(graph.GetOutputLayers().begin(), graph.GetOutputLayers().end(), [=](auto* layer)
1499  {
1500  return layer->GetBindingId() == layerBindingId;
1501  });
1502 
1503  if (it == graph.GetOutputLayers().end())
1504  {
1505  throw MemoryImportException(fmt::format("ImportOutputs: Memory Import failed, unknown LayerBindingId: {}",
1506  layerBindingId));
1507  }
1508 
1509  const Layer* layer = *it;
1510  if (layer->GetType() != LayerType::Output)
1511  {
1512  throw InvalidArgumentException("ImportOutputs: given layer not an OutputLayer");
1513  }
1514 
1515  auto& backend = m_Backends.at(layer->GetBackendId());
1516  if (!HasCapability(BackendOptions::BackendOption{"PreImportIOTensors", true}, backend->GetCapabilities()))
1517  {
1518  std::string er = backend->GetId();
1519  er += " does not have PreImportIOTensors capability";
1520  throw BackendCapabilityException(er);
1521  }
1522 
1523  const InputSlot& inputSlot = layer->GetInputSlots()[0];
1524  ITensorHandleFactory::FactoryId factoryId = inputSlot.GetConnectedOutputSlot()->GetTensorHandleFactoryId();
1525  const TensorInfo& tensorInfo = inputSlot.GetConnectedOutputSlot()->GetTensorInfo();
1526 
1527  ITensorHandleFactory* handleFactory = m_TensorHandleFactoryRegistry.GetFactory(factoryId);
1528  ARMNN_ASSERT(handleFactory);
1529 
1530  ImportedTensorHandlePin importedTensorHandlePin{layerBindingId,
1531  handleFactory->CreateTensorHandle(tensorInfo, false)};
1532 
1533  ITensorHandle* tensorHandle = importedTensorHandlePin.m_TensorHandle.get();
1534 
1535  if (!CheckFlag(tensorHandle->GetImportFlags(), m_NetworkProperties.m_OutputSource))
1536  {
1537  throw MemoryImportException(fmt::format("ImportInputs: Memory Import failed, backend: "
1538  "{} does not support importing from source {}"
1539  , factoryId, m_NetworkProperties.m_OutputSource));
1540  }
1541 
1542  if (tensorHandle->Import(outputTensor.second.GetMemoryArea(), m_NetworkProperties.m_OutputSource))
1543  {
1544  importedOutputs.push_back(m_CurImportedOutputId++);
1545  }
1546  else
1547  {
1548  throw MemoryImportException("ImportInputs: Memory Import failed");
1549  }
1550 
1551  m_PreImportedOutputHandles.push_back(std::move(importedTensorHandlePin));
1552  }
1553 
1554  return importedOutputs;
1555 }
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:63
bool CheckFlag(MemorySourceFlags flags, MemorySource source)

◆ IsAsyncEnabled()

bool IsAsyncEnabled ( )
inline

Definition at line 94 of file LoadedNetwork.hpp.

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

95  {
96  return m_NetworkProperties.m_AsyncEnabled;
97  }

◆ MakeLoadedNetwork()

std::unique_ptr< LoadedNetwork > MakeLoadedNetwork ( std::unique_ptr< IOptimizedNetwork net,
std::string &  errorMessage,
const INetworkProperties networkProperties,
profiling::ProfilingService profilingService 
)
static

Definition at line 82 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(), armnnUtils::Processes::GetCurrentId(), BackendRegistry::GetFactory(), IBackend::GetId(), ProfilerManager::GetInstance(), BackendRegistry::GetMemoryOptimizerStrategies(), Graph::GetNumInputs(), Graph::GetNumOutputs(), TimelineUtilityMethods::GetTimelineUtils(), 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().

86 {
87  std::unique_ptr<LoadedNetwork> loadedNetwork;
88 
89  auto Fail = [&](const std::exception& error) -> std::unique_ptr<LoadedNetwork>
90  {
91  errorMessage = ToErrorMessage("An error occurred when preparing the network workloads: ", error);
92  ARMNN_LOG(error) << errorMessage;
93 
94  return std::unique_ptr<LoadedNetwork>();
95  };
96 
97  try
98  {
99  loadedNetwork.reset(new LoadedNetwork(std::move(net), networkProperties, profilingService));
100  }
101  catch (const armnn::RuntimeException& error)
102  {
103  return Fail(error);
104  }
105  catch (const armnn::Exception& error)
106  {
107  return Fail(error);
108  }
109  catch (const std::runtime_error& error)
110  {
111  return Fail(error);
112  }
113 
114  return loadedNetwork;
115 }
#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 ( )

Definition at line 545 of file LoadedNetwork.cpp.

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

546 {
547  ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "LoadNetwork_SendNetworkStructure");
548  Graph& order = m_OptimizedNetwork->pOptimizedNetworkImpl->GetGraph().TopologicalSort();
549  ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
550 
551  std::unique_ptr<TimelineUtilityMethods> timelineUtils =
552  TimelineUtilityMethods::GetTimelineUtils(m_ProfilingService);
553 
554  timelineUtils->CreateTypedEntity(networkGuid, LabelsAndEventClasses::NETWORK_GUID);
555 
556  for (auto&& layer : order)
557  {
558  // Add layer to the post-optimisation network structure
559  AddLayerStructure(timelineUtils, *layer, networkGuid);
560  switch (layer->GetType())
561  {
562  case LayerType::Input:
563  case LayerType::Output:
564  {
565  // Inputs and outputs are treated in a special way - see EnqueueInput() and EnqueueOutput().
566  break;
567  }
568  default:
569  {
570  for (auto& workload : m_WorkloadQueue)
571  {
572  // Add workload to the post-optimisation network structure
573  AddWorkloadStructure(timelineUtils, workload, *layer);
574  }
575  break;
576  }
577  }
578  }
579  // Commit to send the post-optimisation network structure
580  timelineUtils->Commit();
581 }
static std::unique_ptr< TimelineUtilityMethods > GetTimelineUtils(ProfilingService &profilingService)
#define ARMNN_SCOPED_PROFILING_EVENT(backendId, name)
Definition: Profiling.hpp:220

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