blob: 4f68c3bcc7734460deb60e1f62cb44e2e7835016 [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},
29 {"ProtectedContentAllocation", true}
Finn Williamsb9af86e2021-05-26 18:38:12 +010030 });
Sadik Armaganaede8ca2021-03-31 16:12:13 +010031
arovir014424b0a2018-10-04 10:46:04 +010032class ClBackend : public IBackendInternal
33{
34public:
Jan Eilersc1c872f2021-07-22 13:17:04 +010035 ClBackend() : m_CustomAllocator(nullptr) {};
36 ClBackend(std::shared_ptr<ICustomAllocator> allocator)
37 {
38 std::string err;
39 UseCustomMemoryAllocator(allocator, err);
40 }
David Beck9efb57d2018-11-05 13:40:33 +000041 ~ClBackend() = default;
arovir014424b0a2018-10-04 10:46:04 +010042
David Beck3cc9a622018-10-12 10:38:31 +010043 static const BackendId& GetIdStatic();
44 const BackendId& GetId() const override { return GetIdStatic(); }
arovir014424b0a2018-10-04 10:46:04 +010045
Aron Virginas-Tar56055192018-11-12 18:10:43 +000046 IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override;
47
48 IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory(
49 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr) const override;
50
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010051 IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory(
52 TensorHandleFactoryRegistry& registry) const override;
53
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010054 IWorkloadFactoryPtr CreateWorkloadFactory(const IMemoryManagerSharedPtr& memoryManager,
55 const ModelOptions& modelOptions) const override;
Sadik Armagan04a72972020-09-14 15:44:18 +010056
57 IWorkloadFactoryPtr CreateWorkloadFactory(class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry,
58 const ModelOptions& modelOptions) const override;
59
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010060 IWorkloadFactoryPtr CreateWorkloadFactory(class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry,
61 const ModelOptions& modelOptions,
62 MemorySourceFlags inputFlags,
63 MemorySourceFlags outputFlags) const override;
64
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010065 std::vector<ITensorHandleFactory::FactoryId> GetHandleFactoryPreferences() const override;
66
67 void RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry) override;
68
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010069 void RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry,
70 MemorySourceFlags inputFlags,
71 MemorySourceFlags outputFlags) override;
72
David Beck1b61be52018-11-08 09:19:14 +000073 IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions&) const override;
Colm Donelan1aff3932020-02-05 17:48:59 +000074 IBackendInternal::IBackendProfilingContextPtr CreateBackendProfilingContext(
75 const IRuntime::CreationOptions&, IBackendProfilingPtr& backendProfiling) override;
Aron Virginas-Tar56055192018-11-12 18:10:43 +000076
David Beck263e3492018-11-09 14:46:40 +000077 IBackendInternal::Optimizations GetOptimizations() const override;
David Beck111b5d92018-11-12 14:59:37 +000078 IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override;
Sadik Armagan045f6be2020-09-10 13:37:32 +010079 IBackendInternal::ILayerSupportSharedPtr GetLayerSupport(const ModelOptions& modelOptions) const override;
Matteo Martincighadddddb2019-01-24 14:06:23 +000080
Mike Kelly07810fc2020-11-12 10:58:48 +000081 OptimizationViews OptimizeSubgraphView(const SubgraphView& subgraph,
82 const ModelOptions& modelOptions) const override;
Sadik Armagan045f6be2020-09-10 13:37:32 +010083
84 IBackendInternal::IBackendSpecificModelContextPtr CreateBackendSpecificModelContext(
85 const ModelOptions& modelOptions) const override;
Sadik Armaganaede8ca2021-03-31 16:12:13 +010086
Finn Williamsb9af86e2021-05-26 18:38:12 +010087 BackendCapabilities GetCapabilities() const override
88 {
89 return gpuAccCapabilities;
90 };
Jan Eilers15fcc7e2021-07-14 13:50:15 +010091
Jan Eilersc1c872f2021-07-22 13:17:04 +010092 virtual bool UseCustomMemoryAllocator(std::shared_ptr<ICustomAllocator> allocator,
93 armnn::Optional<std::string&> errMsg) override
Jan Eilers15fcc7e2021-07-14 13:50:15 +010094 {
95 IgnoreUnused(errMsg);
Jan Eilersc1c872f2021-07-22 13:17:04 +010096 ARMNN_LOG(info) << "Using Custom Allocator for ClBackend";
Jan Eilers15fcc7e2021-07-14 13:50:15 +010097
98 // Set flag to signal the backend to use a custom memory allocator
Jan Eilersc1c872f2021-07-22 13:17:04 +010099 m_CustomAllocator = std::make_shared<ClBackendCustomAllocatorWrapper>(std::move(allocator));
100 m_UsingCustomAllocator = true;
101 return m_UsingCustomAllocator;
Jan Eilers15fcc7e2021-07-14 13:50:15 +0100102 }
103
Jan Eilersc1c872f2021-07-22 13:17:04 +0100104 // Cl requires a arm_compute::IAllocator we wrap the Arm NN ICustomAllocator to achieve this
105 class ClBackendCustomAllocatorWrapper : public arm_compute::IAllocator
106 {
107 public:
108 ClBackendCustomAllocatorWrapper(std::shared_ptr<ICustomAllocator> alloc) : m_CustomAllocator(alloc)
109 {}
110 // Inherited methods overridden:
111 void* allocate(size_t size, size_t alignment) override
112 {
113 auto alloc = m_CustomAllocator->allocate(size, alignment);
114 return MapAllocatedMemory(alloc, size, m_CustomAllocator->GetMemorySourceType());
115 }
116 void free(void* ptr) override
117 {
118 auto hostMemPtr = m_AllocatedBufferMappings[ptr];
119 clReleaseMemObject(static_cast<cl_mem>(ptr));
120 m_CustomAllocator->free(hostMemPtr);
121 }
122 std::unique_ptr<arm_compute::IMemoryRegion> make_region(size_t size, size_t alignment) override
123 {
124 auto hostMemPtr = m_CustomAllocator->allocate(size, alignment);
125 cl_mem buffer = MapAllocatedMemory(hostMemPtr, size, m_CustomAllocator->GetMemorySourceType());
126
David Monahane9b12302021-08-12 10:20:21 +0100127 return std::make_unique<ClBackendCustomAllocatorMemoryRegion>(cl::Buffer(buffer),
128 hostMemPtr,
129 m_CustomAllocator->GetMemorySourceType());
Jan Eilersc1c872f2021-07-22 13:17:04 +0100130 }
131 private:
132 cl_mem MapAllocatedMemory(void* memory, size_t size, MemorySource source)
133 {
134 // Round the size of the buffer to a multiple of the CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE
135 auto cachelineAlignment =
136 arm_compute::CLKernelLibrary::get().get_device().getInfo<CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE>();
137 auto roundedSize = cachelineAlignment + size - (size % cachelineAlignment);
138
139 if (source == MemorySource::Malloc)
140 {
141 const cl_import_properties_arm importProperties[] =
142 {
Francis Murtagh9db96e02021-08-13 16:15:09 +0100143 CL_IMPORT_TYPE_ARM,
144 CL_IMPORT_TYPE_HOST_ARM,
145 0
Jan Eilersc1c872f2021-07-22 13:17:04 +0100146 };
147 cl_int error = CL_SUCCESS;
148 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
149 CL_MEM_READ_WRITE,
150 importProperties,
151 memory,
152 roundedSize,
153 &error);
154 if (error == CL_SUCCESS)
155 {
156 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
157 return buffer;
158 }
159 throw armnn::Exception(
160 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: " + std::to_string(error));
161 }
David Monahane9b12302021-08-12 10:20:21 +0100162 else if (source == MemorySource::DmaBuf)
163 {
164 const cl_import_properties_arm importProperties[] =
165 {
Francis Murtagh9db96e02021-08-13 16:15:09 +0100166 CL_IMPORT_TYPE_ARM,
167 CL_IMPORT_TYPE_DMA_BUF_ARM,
168 CL_IMPORT_DMA_BUF_DATA_CONSISTENCY_WITH_HOST_ARM,
169 CL_TRUE,
170 0
171 };
172 cl_int error = CL_SUCCESS;
173 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
174 CL_MEM_READ_WRITE,
175 importProperties,
176 memory,
177 roundedSize,
178 &error);
179 if (error == CL_SUCCESS)
180 {
181 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
182 return buffer;
183 }
184 throw armnn::Exception(
185 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: "
186 + std::to_string(error));
187 }
188 else if (source == MemorySource::DmaBufProtected)
189 {
190 const cl_import_properties_arm importProperties[] =
191 {
192 CL_IMPORT_TYPE_ARM,
193 CL_IMPORT_TYPE_DMA_BUF_ARM,
194 CL_IMPORT_TYPE_PROTECTED_ARM,
195 CL_TRUE,
196 0
David Monahane9b12302021-08-12 10:20:21 +0100197 };
198 cl_int error = CL_SUCCESS;
199 cl_mem buffer = clImportMemoryARM(arm_compute::CLKernelLibrary::get().context().get(),
200 CL_MEM_READ_WRITE,
201 importProperties,
202 memory,
203 roundedSize,
204 &error);
205 if (error == CL_SUCCESS)
206 {
207 m_AllocatedBufferMappings.insert(std::make_pair(static_cast<void *>(buffer), memory));
208 return buffer;
209 }
210 throw armnn::Exception(
211 "Mapping allocated memory from CustomMemoryAllocator failed, errcode: "
212 + std::to_string(error));
213 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100214 throw armnn::Exception(
215 "Attempting to allocate memory with unsupported MemorySource type in CustomAllocator");
216 }
217 std::shared_ptr<ICustomAllocator> m_CustomAllocator;
218 std::map<void*, void*> m_AllocatedBufferMappings;
219 };
220
221 class ClBackendCustomAllocatorMemoryRegion : public arm_compute::ICLMemoryRegion
222 {
223 public:
224 // 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 +0100225 ClBackendCustomAllocatorMemoryRegion(const cl::Buffer &buffer, void* hostMemPtr, armnn::MemorySource source)
Jan Eilersc1c872f2021-07-22 13:17:04 +0100226 : ICLMemoryRegion(buffer.getInfo<CL_MEM_SIZE>())
227 {
228 _mem = buffer;
229 m_HostMemPtr = hostMemPtr;
David Monahane9b12302021-08-12 10:20:21 +0100230 m_MemorySource = source;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100231 }
232
233 // Inherited methods overridden :
234 void* ptr() override
235 {
236 return nullptr;
237 }
238
239 void* map(cl::CommandQueue &q, bool blocking) override
240 {
241 armnn::IgnoreUnused(q, blocking);
242 if (m_HostMemPtr == nullptr)
243 {
244 throw armnn::Exception("ClBackend: Attempting to map memory with an invalid host ptr");
245 }
David Monahane9b12302021-08-12 10:20:21 +0100246 if (_mapping != nullptr)
247 {
248 throw armnn::Exception("ClBackend: Attempting to map memory which has not yet been unmapped");
249 }
250 switch (m_MemorySource)
251 {
252 case armnn::MemorySource::Malloc:
253 _mapping = m_HostMemPtr;
254 return _mapping;
255 break;
256 case armnn::MemorySource::DmaBuf:
Francis Murtagh9db96e02021-08-13 16:15:09 +0100257 case armnn::MemorySource::DmaBufProtected:
David Monahane9b12302021-08-12 10:20:21 +0100258 // If the source is a Dmabuf then the memory ptr should be pointing to an integer value for the fd
259 _mapping = mmap(NULL, _size, PROT_WRITE, MAP_SHARED, *(reinterpret_cast<int*>(m_HostMemPtr)), 0);
260 return _mapping;
261 break;
262 default:
263 throw armnn::Exception("ClBackend: Attempting to map imported memory without a valid source");
264 break;
265 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100266 }
267
268 void unmap(cl::CommandQueue &q) override
269 {
270 armnn::IgnoreUnused(q);
David Monahane9b12302021-08-12 10:20:21 +0100271 switch (m_MemorySource)
272 {
273 case armnn::MemorySource::Malloc:
274 _mapping = nullptr;
275 break;
276 case armnn::MemorySource::DmaBuf:
Francis Murtagh9db96e02021-08-13 16:15:09 +0100277 case armnn::MemorySource::DmaBufProtected:
David Monahane9b12302021-08-12 10:20:21 +0100278 munmap(_mapping, _size);
279 _mapping = nullptr;
280 break;
281 default:
282 throw armnn::Exception("ClBackend: Attempting to unmap imported memory without a valid source");
283 break;
284 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100285 }
David Monahane9b12302021-08-12 10:20:21 +0100286 private:
Jan Eilersc1c872f2021-07-22 13:17:04 +0100287 void* m_HostMemPtr = nullptr;
David Monahane9b12302021-08-12 10:20:21 +0100288 armnn::MemorySource m_MemorySource;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100289 };
290
291 std::shared_ptr<ClBackendCustomAllocatorWrapper> m_CustomAllocator;
292 bool m_UsingCustomAllocator = false;
arovir014424b0a2018-10-04 10:46:04 +0100293};
294
Matteo Martincighadddddb2019-01-24 14:06:23 +0000295} // namespace armnn