xref: /aosp_15_r20/external/armnn/src/armnn/WorkingMemHandle.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "WorkingMemHandle.hpp"
7 #include "Network.hpp"
8 #include <armnn/backends/IMemoryManager.hpp>
9 #include <armnn/backends/TensorHandle.hpp>
10 #include <fmt/format.h>
11 
12 namespace armnn
13 {
14 
15 namespace experimental
16 {
17 
WorkingMemHandle(NetworkId networkId,std::vector<InputMemDescriptorCoords> inputLayerInfo,std::vector<OutputMemDescriptorCoords> outputLayerInfo,std::vector<WorkingMemDescriptor> workingMemDescriptors,std::unique_ptr<MemoryManager> memoryManager,std::vector<std::pair<std::shared_ptr<TensorMemory>,MemorySource>> tensorMemory,std::vector<std::unique_ptr<ITensorHandle>> managedTensorHandles,std::vector<std::unique_ptr<ITensorHandle>> unmanagedTensorHandles,std::vector<std::pair<BackendId,ExecutionData>> executionDataVec,BackendPtrMap * backends)18 WorkingMemHandle::WorkingMemHandle(NetworkId networkId,
19         std::vector<InputMemDescriptorCoords> inputLayerInfo,
20         std::vector<OutputMemDescriptorCoords> outputLayerInfo,
21         std::vector<WorkingMemDescriptor> workingMemDescriptors,
22         std::unique_ptr<MemoryManager> memoryManager,
23         std::vector<std::pair<std::shared_ptr<TensorMemory>, MemorySource>> tensorMemory,
24         std::vector<std::unique_ptr<ITensorHandle>> managedTensorHandles,
25         std::vector<std::unique_ptr<ITensorHandle>> unmanagedTensorHandles,
26         std::vector<std::pair<BackendId, ExecutionData>> executionDataVec,
27         BackendPtrMap* backends)
28     : m_NetworkId(networkId)
29     , m_WorkingMemDescriptors(workingMemDescriptors)
30     , m_MemoryManager(std::move(memoryManager))
31     , m_TensorMemory(std::move(tensorMemory))
32     , m_ManagedTensorHandles(std::move(managedTensorHandles))
33     , m_UnmanagedTensorHandles(std::move(unmanagedTensorHandles))
34     , m_InputSize(numeric_cast<DifferenceType>(inputLayerInfo.size()))
35     , m_IsAllocated(false)
36     , m_ExecutionDataVec(executionDataVec)
37     , m_Backends(backends)
38 {
39     for (const auto& inputInfo : inputLayerInfo)
40     {
41         m_InputValidationMap[inputInfo.m_LayerBindingId] = false;
42 
43         // Map the LayerBindingIds to the corresponding input ITensorHandle*
44         auto memDesc = m_WorkingMemDescriptors.at(inputInfo.m_InputSlotCoords[0].first);
45         ITensorHandle* inputTensorHandle = memDesc.m_Inputs[inputInfo.m_InputSlotCoords[0].second];
46         m_InputHandleMap[inputInfo.m_LayerBindingId] = inputTensorHandle;
47 
48         // For every input we need to store all locations from which that input's ITensorHandle* is read.
49         // So we can, at a later point, swap in and out the ITensorHandle* at that location.
50         for (auto inputSlot : inputInfo.m_InputSlotCoords)
51         {
52             WorkingMemDescriptor& workingMemDescriptor = m_WorkingMemDescriptors.at(inputSlot.first);
53 
54             auto inputPos = workingMemDescriptor.m_Inputs.begin();
55 
56             // The DifferenceType of a vector can be unsigned int or signed int depending on the std implementation
57             // This cast removes any conversion warnings
58             inputPos += numeric_cast<DifferenceType>(inputSlot.second);
59             m_InputConnectionMap[inputInfo.m_LayerBindingId].push_back(inputPos);
60         }
61     }
62     size_t bindingIdCount = inputLayerInfo.size();
63     for (const auto& outputInfo : outputLayerInfo)
64     {
65         for (auto bindingId : outputInfo.m_LayerBindingIds)
66         {
67             m_OutputValidationMap[bindingId] = false;
68 
69             // Store the outputSlot position of the tensorhandle
70             auto outputPos = m_WorkingMemDescriptors.at(outputInfo.m_OutputSlotCoords.first).m_Outputs.begin();
71             outputPos += numeric_cast<DifferenceType>(outputInfo.m_OutputSlotCoords.second);
72 
73             m_OutputHandleMap[bindingId] = *outputPos;
74         }
75         bindingIdCount += outputInfo.m_LayerBindingIds.size();
76         // More than one layerBinding id means the tensorhandle is connected to more than one OutputLayer.
77         // Importing in this case would likely cause unexpected behaviour, so we disallow it.
78         if (outputInfo.m_LayerBindingIds.size() != 1)
79         {
80             continue;
81         }
82 
83         // Store the inputSlot positions of the tensorhandle
84         for (auto outputSlot : outputInfo.m_InputSlotCoords)
85         {
86             WorkingMemDescriptor& workingMemDescriptor = m_WorkingMemDescriptors.at(outputSlot.first);
87 
88             auto inputPos = workingMemDescriptor.m_Inputs.begin();
89 
90             // The DifferenceType of a vector can be unsigned int or signed int depending on the std implementation
91             // This cast removes any conversion warnings
92             inputPos += numeric_cast<DifferenceType>(outputSlot.second);
93             m_OutputConnectionMap[outputInfo.m_LayerBindingIds[0]].push_back(inputPos);
94         }
95     }
96     m_BindingIdVec = std::vector<LayerBindingId>(bindingIdCount);
97     IgnoreUnused(m_UnmanagedTensorHandles);
98 }
99 
Allocate()100 void WorkingMemHandle::Allocate()
101 {
102     if (m_IsAllocated)
103     {
104         return;
105     }
106     m_IsAllocated = true;
107 
108     m_MemoryManager->Allocate();
109 
110     for (unsigned int i = 0; i < m_TensorMemory.size(); ++i)
111     {
112         m_ManagedTensorHandles[i]->Import(m_TensorMemory[i].first->m_Data, m_TensorMemory[i].second);
113     }
114 
115     // Assign previously allocated ExecutionData. Needs to be assigned after allocation so the void* are allocated.
116     for (unsigned int i = 0; i < m_ExecutionDataVec.size(); ++i)
117     {
118         auto& backend = m_Backends->at(m_ExecutionDataVec[i].first);
119 
120         ExecutionData executionData = backend->CreateExecutionData(GetWorkingMemDescriptorAt(i));
121         m_ExecutionDataVec[i].second = executionData;
122     }
123 }
124 
Free()125 void WorkingMemHandle::Free()
126 {
127     if (!m_IsAllocated)
128     {
129         return;
130     }
131     m_IsAllocated = false;
132 
133     m_MemoryManager->Deallocate();
134 }
135 
MemSyncOutputs()136 void WorkingMemHandle::MemSyncOutputs()
137 {
138     for (auto output : m_OutputConnectionMap)
139     {
140         (*output.second[0])->Map(true);
141         (*output.second[0])->Unmap();
142     }
143 }
144 
ValidateBindingIds()145 void WorkingMemHandle::ValidateBindingIds()
146 {
147     auto resetInputValidationMap = [&]()
148     {
149         for (auto& pair: m_InputValidationMap)
150         {
151             pair.second = false;
152         }
153     };
154 
155     auto resetOutputValidationMap = [&]()
156     {
157         for (auto& pair: m_OutputValidationMap)
158         {
159             pair.second = false;
160         }
161     };
162 
163     std::for_each(m_BindingIdVec.begin(), m_BindingIdVec.begin() + m_InputSize, [&](LayerBindingId id)
164     {
165         try
166         {
167             bool& isUsed = m_InputValidationMap.at(id);
168             if (isUsed)
169             {
170                 resetInputValidationMap();
171                 throw InvalidArgumentException(fmt::format("Duplicate Input LayerBindingId: {}", id));
172             }
173             isUsed = true;
174         }
175         catch (const std::out_of_range&)
176         {
177             resetInputValidationMap();
178             throw InvalidArgumentException(fmt::format("Unknown Input LayerBindingId: {}", id));
179         }
180     });
181     resetInputValidationMap();
182 
183     std::for_each(m_BindingIdVec.begin() + m_InputSize, m_BindingIdVec.end(), [&](LayerBindingId id)
184     {
185         try
186         {
187             bool& isUsed = m_OutputValidationMap.at(id);
188             if (isUsed)
189             {
190                 resetOutputValidationMap();
191                 throw InvalidArgumentException(fmt::format("Duplicate Output LayerBindingId: {}", id));
192             }
193             isUsed = true;
194         }
195         catch (const std::out_of_range&)
196         {
197             resetOutputValidationMap();
198             throw InvalidArgumentException(fmt::format("Unknown Output LayerBindingId: {}", id));
199         }
200     });
201     resetOutputValidationMap();
202 }
203 
204 } // end experimental namespace
205 
206 } // end armnn namespace
207