blob: ce56c3025c344cf6411f28f88ebbec62e77401a3 [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},
Cathal Corbett4452baf2022-05-13 09:55:59 +010030 {"ConstantTensorsAsInputs", true},
Sadik Armaganc8402632021-09-10 11:40:54 +010031 {"PreImportIOTensors", false},
Finn Williamsb1aad422021-10-28 19:07:32 +010032 {"ExternallyManagedMemory", true},
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
David Monahan6642b8a2021-11-04 16:31:46 +000091 std::unique_ptr<ICustomAllocator> GetDefaultAllocator() const override;
92
Finn Williamsb9af86e2021-05-26 18:38:12 +010093 BackendCapabilities GetCapabilities() const override
94 {
95 return gpuAccCapabilities;
96 };
Jan Eilers15fcc7e2021-07-14 13:50:15 +010097
Jan Eilersc1c872f2021-07-22 13:17:04 +010098 virtual bool UseCustomMemoryAllocator(std::shared_ptr<ICustomAllocator> allocator,
99 armnn::Optional<std::string&> errMsg) override
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100100 {
101 IgnoreUnused(errMsg);
Jan Eilersc1c872f2021-07-22 13:17:04 +0100102 ARMNN_LOG(info) << "Using Custom Allocator for ClBackend";
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100103
104 // Set flag to signal the backend to use a custom memory allocator
Jan Eilersc1c872f2021-07-22 13:17:04 +0100105 m_CustomAllocator = std::make_shared<ClBackendCustomAllocatorWrapper>(std::move(allocator));
106 m_UsingCustomAllocator = true;
107 return m_UsingCustomAllocator;
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100108 }
109
Sadik Armaganb7851f92021-10-06 16:37:02 +0100110 virtual unsigned int GetNumberOfCacheFiles() const override { return 1; }
111
Jan Eilersc1c872f2021-07-22 13:17:04 +0100112 // Cl requires a arm_compute::IAllocator we wrap the Arm NN ICustomAllocator to achieve this
113 class ClBackendCustomAllocatorWrapper : public arm_compute::IAllocator
114 {
115 public:
116 ClBackendCustomAllocatorWrapper(std::shared_ptr<ICustomAllocator> alloc) : m_CustomAllocator(alloc)
117 {}
118 // Inherited methods overridden:
119 void* allocate(size_t size, size_t alignment) override
120 {
121 auto alloc = m_CustomAllocator->allocate(size, alignment);
122 return MapAllocatedMemory(alloc, size, m_CustomAllocator->GetMemorySourceType());
123 }
124 void free(void* ptr) override
125 {
126 auto hostMemPtr = m_AllocatedBufferMappings[ptr];
127 clReleaseMemObject(static_cast<cl_mem>(ptr));
128 m_CustomAllocator->free(hostMemPtr);
129 }
130 std::unique_ptr<arm_compute::IMemoryRegion> make_region(size_t size, size_t alignment) override
131 {
132 auto hostMemPtr = m_CustomAllocator->allocate(size, alignment);
133 cl_mem buffer = MapAllocatedMemory(hostMemPtr, size, m_CustomAllocator->GetMemorySourceType());
134
David Monahane9b12302021-08-12 10:20:21 +0100135 return std::make_unique<ClBackendCustomAllocatorMemoryRegion>(cl::Buffer(buffer),
136 hostMemPtr,
137 m_CustomAllocator->GetMemorySourceType());
Jan Eilersc1c872f2021-07-22 13:17:04 +0100138 }
139 private:
140 cl_mem MapAllocatedMemory(void* memory, size_t size, MemorySource source)
141 {
142 // Round the size of the buffer to a multiple of the CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE
143 auto cachelineAlignment =
144 arm_compute::CLKernelLibrary::get().get_device().getInfo<CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE>();
145 auto roundedSize = cachelineAlignment + size - (size % cachelineAlignment);
146
147 if (source == MemorySource::Malloc)
148 {
149 const cl_import_properties_arm importProperties[] =
150 {
Francis Murtagh9db96e02021-08-13 16:15:09 +0100151 CL_IMPORT_TYPE_ARM,
152 CL_IMPORT_TYPE_HOST_ARM,
153 0
Jan Eilersc1c872f2021-07-22 13:17:04 +0100154 };
155 cl_int error = CL_SUCCESS;
156 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
157 CL_MEM_READ_WRITE,
158 importProperties,
159 memory,
160 roundedSize,
161 &error);
162 if (error == CL_SUCCESS)
163 {
164 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
165 return buffer;
166 }
167 throw armnn::Exception(
168 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: " + std::to_string(error));
169 }
David Monahane9b12302021-08-12 10:20:21 +0100170 else if (source == MemorySource::DmaBuf)
171 {
172 const cl_import_properties_arm importProperties[] =
173 {
Francis Murtagh9db96e02021-08-13 16:15:09 +0100174 CL_IMPORT_TYPE_ARM,
175 CL_IMPORT_TYPE_DMA_BUF_ARM,
176 CL_IMPORT_DMA_BUF_DATA_CONSISTENCY_WITH_HOST_ARM,
177 CL_TRUE,
178 0
179 };
180 cl_int error = CL_SUCCESS;
181 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
182 CL_MEM_READ_WRITE,
183 importProperties,
184 memory,
185 roundedSize,
186 &error);
187 if (error == CL_SUCCESS)
188 {
189 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
190 return buffer;
191 }
192 throw armnn::Exception(
193 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: "
194 + std::to_string(error));
195 }
196 else if (source == MemorySource::DmaBufProtected)
197 {
198 const cl_import_properties_arm importProperties[] =
199 {
200 CL_IMPORT_TYPE_ARM,
201 CL_IMPORT_TYPE_DMA_BUF_ARM,
202 CL_IMPORT_TYPE_PROTECTED_ARM,
203 CL_TRUE,
204 0
David Monahane9b12302021-08-12 10:20:21 +0100205 };
206 cl_int error = CL_SUCCESS;
207 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
208 CL_MEM_READ_WRITE,
209 importProperties,
210 memory,
211 roundedSize,
212 &error);
213 if (error == CL_SUCCESS)
214 {
215 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
216 return buffer;
217 }
218 throw armnn::Exception(
219 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: "
220 + std::to_string(error));
221 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100222 throw armnn::Exception(
223 "Attempting to allocate memory with unsupported MemorySource type in CustomAllocator");
224 }
225 std::shared_ptr<ICustomAllocator> m_CustomAllocator;
226 std::map<void*, void*> m_AllocatedBufferMappings;
227 };
228
229 class ClBackendCustomAllocatorMemoryRegion : public arm_compute::ICLMemoryRegion
230 {
231 public:
232 // 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 +0100233 ClBackendCustomAllocatorMemoryRegion(const cl::Buffer &buffer, void* hostMemPtr, armnn::MemorySource source)
Jan Eilersc1c872f2021-07-22 13:17:04 +0100234 : ICLMemoryRegion(buffer.getInfo<CL_MEM_SIZE>())
235 {
236 _mem = buffer;
237 m_HostMemPtr = hostMemPtr;
David Monahane9b12302021-08-12 10:20:21 +0100238 m_MemorySource = source;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100239 }
240
241 // Inherited methods overridden :
242 void* ptr() override
243 {
244 return nullptr;
245 }
246
247 void* map(cl::CommandQueue &q, bool blocking) override
248 {
249 armnn::IgnoreUnused(q, blocking);
250 if (m_HostMemPtr == nullptr)
251 {
252 throw armnn::Exception("ClBackend: Attempting to map memory with an invalid host ptr");
253 }
David Monahane9b12302021-08-12 10:20:21 +0100254 if (_mapping != nullptr)
255 {
256 throw armnn::Exception("ClBackend: Attempting to map memory which has not yet been unmapped");
257 }
258 switch (m_MemorySource)
259 {
260 case armnn::MemorySource::Malloc:
261 _mapping = m_HostMemPtr;
262 return _mapping;
263 break;
264 case armnn::MemorySource::DmaBuf:
Francis Murtagh9db96e02021-08-13 16:15:09 +0100265 case armnn::MemorySource::DmaBufProtected:
David Monahane9b12302021-08-12 10:20:21 +0100266 // If the source is a Dmabuf then the memory ptr should be pointing to an integer value for the fd
267 _mapping = mmap(NULL, _size, PROT_WRITE, MAP_SHARED, *(reinterpret_cast<int*>(m_HostMemPtr)), 0);
268 return _mapping;
269 break;
270 default:
271 throw armnn::Exception("ClBackend: Attempting to map imported memory without a valid source");
272 break;
273 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100274 }
275
276 void unmap(cl::CommandQueue &q) override
277 {
278 armnn::IgnoreUnused(q);
David Monahane9b12302021-08-12 10:20:21 +0100279 switch (m_MemorySource)
280 {
281 case armnn::MemorySource::Malloc:
282 _mapping = nullptr;
283 break;
284 case armnn::MemorySource::DmaBuf:
Francis Murtagh9db96e02021-08-13 16:15:09 +0100285 case armnn::MemorySource::DmaBufProtected:
David Monahane9b12302021-08-12 10:20:21 +0100286 munmap(_mapping, _size);
287 _mapping = nullptr;
288 break;
289 default:
290 throw armnn::Exception("ClBackend: Attempting to unmap imported memory without a valid source");
291 break;
292 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100293 }
David Monahane9b12302021-08-12 10:20:21 +0100294 private:
Jan Eilersc1c872f2021-07-22 13:17:04 +0100295 void* m_HostMemPtr = nullptr;
David Monahane9b12302021-08-12 10:20:21 +0100296 armnn::MemorySource m_MemorySource;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100297 };
298
299 std::shared_ptr<ClBackendCustomAllocatorWrapper> m_CustomAllocator;
300 bool m_UsingCustomAllocator = false;
arovir014424b0a2018-10-04 10:46:04 +0100301};
302
Matteo Martincighadddddb2019-01-24 14:06:23 +0000303} // namespace armnn