blob: e0708d18e2c9eeb4aff326f74ffc4100f647317e [file] [log] [blame]
arovir014424b0a2018-10-04 10:46:04 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5#pragma once
6
Matteo Martincighe5b8eb92019-11-28 15:45:42 +00007#include <armnn/backends/IBackendInternal.hpp>
arovir014424b0a2018-10-04 10:46:04 +01008
Jan Eilersc1c872f2021-07-22 13:17:04 +01009#include <arm_compute/core/Types.h>
10#include <arm_compute/runtime/CL/CLBufferAllocator.h>
11
12#include <aclCommon/BaseMemoryManager.hpp>
13#include <arm_compute/runtime/CL/CLMemoryRegion.h>
14
15#include <arm_compute/core/CL/CLKernelLibrary.h>
16#include <CL/cl_ext.h>
17
David Monahane9b12302021-08-12 10:20:21 +010018// System includes for mapping and unmapping memory
19#include <sys/mman.h>
20
arovir014424b0a2018-10-04 10:46:04 +010021namespace armnn
22{
23
Finn Williamsb9af86e2021-05-26 18:38:12 +010024// add new capabilities here..
25const BackendCapabilities gpuAccCapabilities("GpuAcc",
26 {
27 {"NonConstWeights", false},
Jan Eilers15fcc7e2021-07-14 13:50:15 +010028 {"AsyncExecution", false},
Finn Williamsdbf5f312021-08-26 11:08:01 +010029 {"ProtectedContentAllocation", true},
30 {"ConstantTensorsAsInputs", false},
Sadik Armaganc8402632021-09-10 11:40:54 +010031 {"PreImportIOTensors", false},
32 {"ExternallyManagedMemory", false},
Sadik Armaganb8a26d82021-10-04 15:13:11 +010033 {"MultiAxisPacking", false},
34 {"SingleAxisPacking", true}
Finn Williamsb9af86e2021-05-26 18:38:12 +010035 });
Sadik Armaganaede8ca2021-03-31 16:12:13 +010036
arovir014424b0a2018-10-04 10:46:04 +010037class ClBackend : public IBackendInternal
38{
39public:
Jan Eilersc1c872f2021-07-22 13:17:04 +010040 ClBackend() : m_CustomAllocator(nullptr) {};
41 ClBackend(std::shared_ptr<ICustomAllocator> allocator)
42 {
43 std::string err;
44 UseCustomMemoryAllocator(allocator, err);
45 }
David Beck9efb57d2018-11-05 13:40:33 +000046 ~ClBackend() = default;
arovir014424b0a2018-10-04 10:46:04 +010047
David Beck3cc9a622018-10-12 10:38:31 +010048 static const BackendId& GetIdStatic();
49 const BackendId& GetId() const override { return GetIdStatic(); }
arovir014424b0a2018-10-04 10:46:04 +010050
Aron Virginas-Tar56055192018-11-12 18:10:43 +000051 IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override;
52
53 IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory(
54 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr) const override;
55
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010056 IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory(
57 TensorHandleFactoryRegistry& registry) const override;
58
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010059 IWorkloadFactoryPtr CreateWorkloadFactory(const IMemoryManagerSharedPtr& memoryManager,
60 const ModelOptions& modelOptions) const override;
Sadik Armagan04a72972020-09-14 15:44:18 +010061
62 IWorkloadFactoryPtr CreateWorkloadFactory(class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry,
63 const ModelOptions& modelOptions) const override;
64
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010065 IWorkloadFactoryPtr CreateWorkloadFactory(class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry,
66 const ModelOptions& modelOptions,
67 MemorySourceFlags inputFlags,
68 MemorySourceFlags outputFlags) const override;
69
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010070 std::vector<ITensorHandleFactory::FactoryId> GetHandleFactoryPreferences() const override;
71
72 void RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry) override;
73
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010074 void RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry,
75 MemorySourceFlags inputFlags,
76 MemorySourceFlags outputFlags) override;
77
David Beck1b61be52018-11-08 09:19:14 +000078 IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions&) const override;
Colm Donelan1aff3932020-02-05 17:48:59 +000079 IBackendInternal::IBackendProfilingContextPtr CreateBackendProfilingContext(
80 const IRuntime::CreationOptions&, IBackendProfilingPtr& backendProfiling) override;
Aron Virginas-Tar56055192018-11-12 18:10:43 +000081
David Beck111b5d92018-11-12 14:59:37 +000082 IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override;
Sadik Armagan045f6be2020-09-10 13:37:32 +010083 IBackendInternal::ILayerSupportSharedPtr GetLayerSupport(const ModelOptions& modelOptions) const override;
Matteo Martincighadddddb2019-01-24 14:06:23 +000084
Mike Kelly07810fc2020-11-12 10:58:48 +000085 OptimizationViews OptimizeSubgraphView(const SubgraphView& subgraph,
86 const ModelOptions& modelOptions) const override;
Sadik Armagan045f6be2020-09-10 13:37:32 +010087
88 IBackendInternal::IBackendSpecificModelContextPtr CreateBackendSpecificModelContext(
89 const ModelOptions& modelOptions) const override;
Sadik Armaganaede8ca2021-03-31 16:12:13 +010090
Finn Williamsb9af86e2021-05-26 18:38:12 +010091 BackendCapabilities GetCapabilities() const override
92 {
93 return gpuAccCapabilities;
94 };
Jan Eilers15fcc7e2021-07-14 13:50:15 +010095
Jan Eilersc1c872f2021-07-22 13:17:04 +010096 virtual bool UseCustomMemoryAllocator(std::shared_ptr<ICustomAllocator> allocator,
97 armnn::Optional<std::string&> errMsg) override
Jan Eilers15fcc7e2021-07-14 13:50:15 +010098 {
99 IgnoreUnused(errMsg);
Jan Eilersc1c872f2021-07-22 13:17:04 +0100100 ARMNN_LOG(info) << "Using Custom Allocator for ClBackend";
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100101
102 // Set flag to signal the backend to use a custom memory allocator
Jan Eilersc1c872f2021-07-22 13:17:04 +0100103 m_CustomAllocator = std::make_shared<ClBackendCustomAllocatorWrapper>(std::move(allocator));
104 m_UsingCustomAllocator = true;
105 return m_UsingCustomAllocator;
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100106 }
107
Jan Eilersc1c872f2021-07-22 13:17:04 +0100108 // Cl requires a arm_compute::IAllocator we wrap the Arm NN ICustomAllocator to achieve this
109 class ClBackendCustomAllocatorWrapper : public arm_compute::IAllocator
110 {
111 public:
112 ClBackendCustomAllocatorWrapper(std::shared_ptr<ICustomAllocator> alloc) : m_CustomAllocator(alloc)
113 {}
114 // Inherited methods overridden:
115 void* allocate(size_t size, size_t alignment) override
116 {
117 auto alloc = m_CustomAllocator->allocate(size, alignment);
118 return MapAllocatedMemory(alloc, size, m_CustomAllocator->GetMemorySourceType());
119 }
120 void free(void* ptr) override
121 {
122 auto hostMemPtr = m_AllocatedBufferMappings[ptr];
123 clReleaseMemObject(static_cast<cl_mem>(ptr));
124 m_CustomAllocator->free(hostMemPtr);
125 }
126 std::unique_ptr<arm_compute::IMemoryRegion> make_region(size_t size, size_t alignment) override
127 {
128 auto hostMemPtr = m_CustomAllocator->allocate(size, alignment);
129 cl_mem buffer = MapAllocatedMemory(hostMemPtr, size, m_CustomAllocator->GetMemorySourceType());
130
David Monahane9b12302021-08-12 10:20:21 +0100131 return std::make_unique<ClBackendCustomAllocatorMemoryRegion>(cl::Buffer(buffer),
132 hostMemPtr,
133 m_CustomAllocator->GetMemorySourceType());
Jan Eilersc1c872f2021-07-22 13:17:04 +0100134 }
135 private:
136 cl_mem MapAllocatedMemory(void* memory, size_t size, MemorySource source)
137 {
138 // Round the size of the buffer to a multiple of the CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE
139 auto cachelineAlignment =
140 arm_compute::CLKernelLibrary::get().get_device().getInfo<CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE>();
141 auto roundedSize = cachelineAlignment + size - (size % cachelineAlignment);
142
143 if (source == MemorySource::Malloc)
144 {
145 const cl_import_properties_arm importProperties[] =
146 {
Francis Murtagh9db96e02021-08-13 16:15:09 +0100147 CL_IMPORT_TYPE_ARM,
148 CL_IMPORT_TYPE_HOST_ARM,
149 0
Jan Eilersc1c872f2021-07-22 13:17:04 +0100150 };
151 cl_int error = CL_SUCCESS;
152 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
153 CL_MEM_READ_WRITE,
154 importProperties,
155 memory,
156 roundedSize,
157 &error);
158 if (error == CL_SUCCESS)
159 {
160 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
161 return buffer;
162 }
163 throw armnn::Exception(
164 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: " + std::to_string(error));
165 }
David Monahane9b12302021-08-12 10:20:21 +0100166 else if (source == MemorySource::DmaBuf)
167 {
168 const cl_import_properties_arm importProperties[] =
169 {
Francis Murtagh9db96e02021-08-13 16:15:09 +0100170 CL_IMPORT_TYPE_ARM,
171 CL_IMPORT_TYPE_DMA_BUF_ARM,
172 CL_IMPORT_DMA_BUF_DATA_CONSISTENCY_WITH_HOST_ARM,
173 CL_TRUE,
174 0
175 };
176 cl_int error = CL_SUCCESS;
177 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
178 CL_MEM_READ_WRITE,
179 importProperties,
180 memory,
181 roundedSize,
182 &error);
183 if (error == CL_SUCCESS)
184 {
185 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
186 return buffer;
187 }
188 throw armnn::Exception(
189 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: "
190 + std::to_string(error));
191 }
192 else if (source == MemorySource::DmaBufProtected)
193 {
194 const cl_import_properties_arm importProperties[] =
195 {
196 CL_IMPORT_TYPE_ARM,
197 CL_IMPORT_TYPE_DMA_BUF_ARM,
198 CL_IMPORT_TYPE_PROTECTED_ARM,
199 CL_TRUE,
200 0
David Monahane9b12302021-08-12 10:20:21 +0100201 };
202 cl_int error = CL_SUCCESS;
203 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
204 CL_MEM_READ_WRITE,
205 importProperties,
206 memory,
207 roundedSize,
208 &error);
209 if (error == CL_SUCCESS)
210 {
211 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
212 return buffer;
213 }
214 throw armnn::Exception(
215 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: "
216 + std::to_string(error));
217 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100218 throw armnn::Exception(
219 "Attempting to allocate memory with unsupported MemorySource type in CustomAllocator");
220 }
221 std::shared_ptr<ICustomAllocator> m_CustomAllocator;
222 std::map<void*, void*> m_AllocatedBufferMappings;
223 };
224
225 class ClBackendCustomAllocatorMemoryRegion : public arm_compute::ICLMemoryRegion
226 {
227 public:
228 // We need to have a new version of ICLMemoryRegion which holds a hostMemPtr to allow for cpu copy access
David Monahane9b12302021-08-12 10:20:21 +0100229 ClBackendCustomAllocatorMemoryRegion(const cl::Buffer &buffer, void* hostMemPtr, armnn::MemorySource source)
Jan Eilersc1c872f2021-07-22 13:17:04 +0100230 : ICLMemoryRegion(buffer.getInfo<CL_MEM_SIZE>())
231 {
232 _mem = buffer;
233 m_HostMemPtr = hostMemPtr;
David Monahane9b12302021-08-12 10:20:21 +0100234 m_MemorySource = source;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100235 }
236
237 // Inherited methods overridden :
238 void* ptr() override
239 {
240 return nullptr;
241 }
242
243 void* map(cl::CommandQueue &q, bool blocking) override
244 {
245 armnn::IgnoreUnused(q, blocking);
246 if (m_HostMemPtr == nullptr)
247 {
248 throw armnn::Exception("ClBackend: Attempting to map memory with an invalid host ptr");
249 }
David Monahane9b12302021-08-12 10:20:21 +0100250 if (_mapping != nullptr)
251 {
252 throw armnn::Exception("ClBackend: Attempting to map memory which has not yet been unmapped");
253 }
254 switch (m_MemorySource)
255 {
256 case armnn::MemorySource::Malloc:
257 _mapping = m_HostMemPtr;
258 return _mapping;
259 break;
260 case armnn::MemorySource::DmaBuf:
Francis Murtagh9db96e02021-08-13 16:15:09 +0100261 case armnn::MemorySource::DmaBufProtected:
David Monahane9b12302021-08-12 10:20:21 +0100262 // If the source is a Dmabuf then the memory ptr should be pointing to an integer value for the fd
263 _mapping = mmap(NULL, _size, PROT_WRITE, MAP_SHARED, *(reinterpret_cast<int*>(m_HostMemPtr)), 0);
264 return _mapping;
265 break;
266 default:
267 throw armnn::Exception("ClBackend: Attempting to map imported memory without a valid source");
268 break;
269 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100270 }
271
272 void unmap(cl::CommandQueue &q) override
273 {
274 armnn::IgnoreUnused(q);
David Monahane9b12302021-08-12 10:20:21 +0100275 switch (m_MemorySource)
276 {
277 case armnn::MemorySource::Malloc:
278 _mapping = nullptr;
279 break;
280 case armnn::MemorySource::DmaBuf:
Francis Murtagh9db96e02021-08-13 16:15:09 +0100281 case armnn::MemorySource::DmaBufProtected:
David Monahane9b12302021-08-12 10:20:21 +0100282 munmap(_mapping, _size);
283 _mapping = nullptr;
284 break;
285 default:
286 throw armnn::Exception("ClBackend: Attempting to unmap imported memory without a valid source");
287 break;
288 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100289 }
David Monahane9b12302021-08-12 10:20:21 +0100290 private:
Jan Eilersc1c872f2021-07-22 13:17:04 +0100291 void* m_HostMemPtr = nullptr;
David Monahane9b12302021-08-12 10:20:21 +0100292 armnn::MemorySource m_MemorySource;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100293 };
294
295 std::shared_ptr<ClBackendCustomAllocatorWrapper> m_CustomAllocator;
296 bool m_UsingCustomAllocator = false;
arovir014424b0a2018-10-04 10:46:04 +0100297};
298
Matteo Martincighadddddb2019-01-24 14:06:23 +0000299} // namespace armnn