blob: ffce8002610055b7beea1b193654773646b11cfe [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
Sadik Armaganb7851f92021-10-06 16:37:02 +0100108 virtual unsigned int GetNumberOfCacheFiles() const override { return 1; }
109
Jan Eilersc1c872f2021-07-22 13:17:04 +0100110 // Cl requires a arm_compute::IAllocator we wrap the Arm NN ICustomAllocator to achieve this
111 class ClBackendCustomAllocatorWrapper : public arm_compute::IAllocator
112 {
113 public:
114 ClBackendCustomAllocatorWrapper(std::shared_ptr<ICustomAllocator> alloc) : m_CustomAllocator(alloc)
115 {}
116 // Inherited methods overridden:
117 void* allocate(size_t size, size_t alignment) override
118 {
119 auto alloc = m_CustomAllocator->allocate(size, alignment);
120 return MapAllocatedMemory(alloc, size, m_CustomAllocator->GetMemorySourceType());
121 }
122 void free(void* ptr) override
123 {
124 auto hostMemPtr = m_AllocatedBufferMappings[ptr];
125 clReleaseMemObject(static_cast<cl_mem>(ptr));
126 m_CustomAllocator->free(hostMemPtr);
127 }
128 std::unique_ptr<arm_compute::IMemoryRegion> make_region(size_t size, size_t alignment) override
129 {
130 auto hostMemPtr = m_CustomAllocator->allocate(size, alignment);
131 cl_mem buffer = MapAllocatedMemory(hostMemPtr, size, m_CustomAllocator->GetMemorySourceType());
132
David Monahane9b12302021-08-12 10:20:21 +0100133 return std::make_unique<ClBackendCustomAllocatorMemoryRegion>(cl::Buffer(buffer),
134 hostMemPtr,
135 m_CustomAllocator->GetMemorySourceType());
Jan Eilersc1c872f2021-07-22 13:17:04 +0100136 }
137 private:
138 cl_mem MapAllocatedMemory(void* memory, size_t size, MemorySource source)
139 {
140 // Round the size of the buffer to a multiple of the CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE
141 auto cachelineAlignment =
142 arm_compute::CLKernelLibrary::get().get_device().getInfo<CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE>();
143 auto roundedSize = cachelineAlignment + size - (size % cachelineAlignment);
144
145 if (source == MemorySource::Malloc)
146 {
147 const cl_import_properties_arm importProperties[] =
148 {
Francis Murtagh9db96e02021-08-13 16:15:09 +0100149 CL_IMPORT_TYPE_ARM,
150 CL_IMPORT_TYPE_HOST_ARM,
151 0
Jan Eilersc1c872f2021-07-22 13:17:04 +0100152 };
153 cl_int error = CL_SUCCESS;
154 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
155 CL_MEM_READ_WRITE,
156 importProperties,
157 memory,
158 roundedSize,
159 &error);
160 if (error == CL_SUCCESS)
161 {
162 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
163 return buffer;
164 }
165 throw armnn::Exception(
166 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: " + std::to_string(error));
167 }
David Monahane9b12302021-08-12 10:20:21 +0100168 else if (source == MemorySource::DmaBuf)
169 {
170 const cl_import_properties_arm importProperties[] =
171 {
Francis Murtagh9db96e02021-08-13 16:15:09 +0100172 CL_IMPORT_TYPE_ARM,
173 CL_IMPORT_TYPE_DMA_BUF_ARM,
174 CL_IMPORT_DMA_BUF_DATA_CONSISTENCY_WITH_HOST_ARM,
175 CL_TRUE,
176 0
177 };
178 cl_int error = CL_SUCCESS;
179 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
180 CL_MEM_READ_WRITE,
181 importProperties,
182 memory,
183 roundedSize,
184 &error);
185 if (error == CL_SUCCESS)
186 {
187 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
188 return buffer;
189 }
190 throw armnn::Exception(
191 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: "
192 + std::to_string(error));
193 }
194 else if (source == MemorySource::DmaBufProtected)
195 {
196 const cl_import_properties_arm importProperties[] =
197 {
198 CL_IMPORT_TYPE_ARM,
199 CL_IMPORT_TYPE_DMA_BUF_ARM,
200 CL_IMPORT_TYPE_PROTECTED_ARM,
201 CL_TRUE,
202 0
David Monahane9b12302021-08-12 10:20:21 +0100203 };
204 cl_int error = CL_SUCCESS;
205 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
206 CL_MEM_READ_WRITE,
207 importProperties,
208 memory,
209 roundedSize,
210 &error);
211 if (error == CL_SUCCESS)
212 {
213 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
214 return buffer;
215 }
216 throw armnn::Exception(
217 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: "
218 + std::to_string(error));
219 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100220 throw armnn::Exception(
221 "Attempting to allocate memory with unsupported MemorySource type in CustomAllocator");
222 }
223 std::shared_ptr<ICustomAllocator> m_CustomAllocator;
224 std::map<void*, void*> m_AllocatedBufferMappings;
225 };
226
227 class ClBackendCustomAllocatorMemoryRegion : public arm_compute::ICLMemoryRegion
228 {
229 public:
230 // 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 +0100231 ClBackendCustomAllocatorMemoryRegion(const cl::Buffer &buffer, void* hostMemPtr, armnn::MemorySource source)
Jan Eilersc1c872f2021-07-22 13:17:04 +0100232 : ICLMemoryRegion(buffer.getInfo<CL_MEM_SIZE>())
233 {
234 _mem = buffer;
235 m_HostMemPtr = hostMemPtr;
David Monahane9b12302021-08-12 10:20:21 +0100236 m_MemorySource = source;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100237 }
238
239 // Inherited methods overridden :
240 void* ptr() override
241 {
242 return nullptr;
243 }
244
245 void* map(cl::CommandQueue &q, bool blocking) override
246 {
247 armnn::IgnoreUnused(q, blocking);
248 if (m_HostMemPtr == nullptr)
249 {
250 throw armnn::Exception("ClBackend: Attempting to map memory with an invalid host ptr");
251 }
David Monahane9b12302021-08-12 10:20:21 +0100252 if (_mapping != nullptr)
253 {
254 throw armnn::Exception("ClBackend: Attempting to map memory which has not yet been unmapped");
255 }
256 switch (m_MemorySource)
257 {
258 case armnn::MemorySource::Malloc:
259 _mapping = m_HostMemPtr;
260 return _mapping;
261 break;
262 case armnn::MemorySource::DmaBuf:
Francis Murtagh9db96e02021-08-13 16:15:09 +0100263 case armnn::MemorySource::DmaBufProtected:
David Monahane9b12302021-08-12 10:20:21 +0100264 // If the source is a Dmabuf then the memory ptr should be pointing to an integer value for the fd
265 _mapping = mmap(NULL, _size, PROT_WRITE, MAP_SHARED, *(reinterpret_cast<int*>(m_HostMemPtr)), 0);
266 return _mapping;
267 break;
268 default:
269 throw armnn::Exception("ClBackend: Attempting to map imported memory without a valid source");
270 break;
271 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100272 }
273
274 void unmap(cl::CommandQueue &q) override
275 {
276 armnn::IgnoreUnused(q);
David Monahane9b12302021-08-12 10:20:21 +0100277 switch (m_MemorySource)
278 {
279 case armnn::MemorySource::Malloc:
280 _mapping = nullptr;
281 break;
282 case armnn::MemorySource::DmaBuf:
Francis Murtagh9db96e02021-08-13 16:15:09 +0100283 case armnn::MemorySource::DmaBufProtected:
David Monahane9b12302021-08-12 10:20:21 +0100284 munmap(_mapping, _size);
285 _mapping = nullptr;
286 break;
287 default:
288 throw armnn::Exception("ClBackend: Attempting to unmap imported memory without a valid source");
289 break;
290 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100291 }
David Monahane9b12302021-08-12 10:20:21 +0100292 private:
Jan Eilersc1c872f2021-07-22 13:17:04 +0100293 void* m_HostMemPtr = nullptr;
David Monahane9b12302021-08-12 10:20:21 +0100294 armnn::MemorySource m_MemorySource;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100295 };
296
297 std::shared_ptr<ClBackendCustomAllocatorWrapper> m_CustomAllocator;
298 bool m_UsingCustomAllocator = false;
arovir014424b0a2018-10-04 10:46:04 +0100299};
300
Matteo Martincighadddddb2019-01-24 14:06:23 +0000301} // namespace armnn