blob: e3ff91c268bdf23c40dd08b44126922bc4175ad9 [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 {
143 CL_IMPORT_TYPE_ARM,
144 CL_IMPORT_TYPE_HOST_ARM,
145 0
146 };
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 {
166 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 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100188 throw armnn::Exception(
189 "Attempting to allocate memory with unsupported MemorySource type in CustomAllocator");
190 }
191 std::shared_ptr<ICustomAllocator> m_CustomAllocator;
192 std::map<void*, void*> m_AllocatedBufferMappings;
193 };
194
195 class ClBackendCustomAllocatorMemoryRegion : public arm_compute::ICLMemoryRegion
196 {
197 public:
198 // 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 +0100199 ClBackendCustomAllocatorMemoryRegion(const cl::Buffer &buffer, void* hostMemPtr, armnn::MemorySource source)
Jan Eilersc1c872f2021-07-22 13:17:04 +0100200 : ICLMemoryRegion(buffer.getInfo<CL_MEM_SIZE>())
201 {
202 _mem = buffer;
203 m_HostMemPtr = hostMemPtr;
David Monahane9b12302021-08-12 10:20:21 +0100204 m_MemorySource = source;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100205 }
206
207 // Inherited methods overridden :
208 void* ptr() override
209 {
210 return nullptr;
211 }
212
213 void* map(cl::CommandQueue &q, bool blocking) override
214 {
215 armnn::IgnoreUnused(q, blocking);
216 if (m_HostMemPtr == nullptr)
217 {
218 throw armnn::Exception("ClBackend: Attempting to map memory with an invalid host ptr");
219 }
David Monahane9b12302021-08-12 10:20:21 +0100220 if (_mapping != nullptr)
221 {
222 throw armnn::Exception("ClBackend: Attempting to map memory which has not yet been unmapped");
223 }
224 switch (m_MemorySource)
225 {
226 case armnn::MemorySource::Malloc:
227 _mapping = m_HostMemPtr;
228 return _mapping;
229 break;
230 case armnn::MemorySource::DmaBuf:
231 // If the source is a Dmabuf then the memory ptr should be pointing to an integer value for the fd
232 _mapping = mmap(NULL, _size, PROT_WRITE, MAP_SHARED, *(reinterpret_cast<int*>(m_HostMemPtr)), 0);
233 return _mapping;
234 break;
235 default:
236 throw armnn::Exception("ClBackend: Attempting to map imported memory without a valid source");
237 break;
238 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100239 }
240
241 void unmap(cl::CommandQueue &q) override
242 {
243 armnn::IgnoreUnused(q);
David Monahane9b12302021-08-12 10:20:21 +0100244 switch (m_MemorySource)
245 {
246 case armnn::MemorySource::Malloc:
247 _mapping = nullptr;
248 break;
249 case armnn::MemorySource::DmaBuf:
250 munmap(_mapping, _size);
251 _mapping = nullptr;
252 break;
253 default:
254 throw armnn::Exception("ClBackend: Attempting to unmap imported memory without a valid source");
255 break;
256 }
Jan Eilersc1c872f2021-07-22 13:17:04 +0100257 }
David Monahane9b12302021-08-12 10:20:21 +0100258 private:
Jan Eilersc1c872f2021-07-22 13:17:04 +0100259 void* m_HostMemPtr = nullptr;
David Monahane9b12302021-08-12 10:20:21 +0100260 armnn::MemorySource m_MemorySource;
Jan Eilersc1c872f2021-07-22 13:17:04 +0100261 };
262
263 std::shared_ptr<ClBackendCustomAllocatorWrapper> m_CustomAllocator;
264 bool m_UsingCustomAllocator = false;
arovir014424b0a2018-10-04 10:46:04 +0100265};
266
Matteo Martincighadddddb2019-01-24 14:06:23 +0000267} // namespace armnn