ArmNN
 21.08
ClBackend.hpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #pragma once
6 
8 
9 #include <arm_compute/core/Types.h>
10 #include <arm_compute/runtime/CL/CLBufferAllocator.h>
11 
13 #include <arm_compute/runtime/CL/CLMemoryRegion.h>
14 
15 #include <arm_compute/core/CL/CLKernelLibrary.h>
16 #include <CL/cl_ext.h>
17 
18 // System includes for mapping and unmapping memory
19 #include <sys/mman.h>
20 
21 namespace armnn
22 {
23 
24 // add new capabilities here..
26  {
27  {"NonConstWeights", false},
28  {"AsyncExecution", false},
29  {"ProtectedContentAllocation", true}
30  });
31 
33 {
34 public:
35  ClBackend() : m_CustomAllocator(nullptr) {};
36  ClBackend(std::shared_ptr<ICustomAllocator> allocator)
37  {
38  std::string err;
39  UseCustomMemoryAllocator(allocator, err);
40  }
41  ~ClBackend() = default;
42 
43  static const BackendId& GetIdStatic();
44  const BackendId& GetId() const override { return GetIdStatic(); }
45 
47 
49  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr) const override;
50 
52  TensorHandleFactoryRegistry& registry) const override;
53 
55  const ModelOptions& modelOptions) const override;
56 
58  const ModelOptions& modelOptions) const override;
59 
61  const ModelOptions& modelOptions,
62  MemorySourceFlags inputFlags,
63  MemorySourceFlags outputFlags) const override;
64 
65  std::vector<ITensorHandleFactory::FactoryId> GetHandleFactoryPreferences() const override;
66 
68 
70  MemorySourceFlags inputFlags,
71  MemorySourceFlags outputFlags) override;
72 
75  const IRuntime::CreationOptions&, IBackendProfilingPtr& backendProfiling) override;
76 
79  IBackendInternal::ILayerSupportSharedPtr GetLayerSupport(const ModelOptions& modelOptions) const override;
80 
82  const ModelOptions& modelOptions) const override;
83 
85  const ModelOptions& modelOptions) const override;
86 
88  {
89  return gpuAccCapabilities;
90  };
91 
92  virtual bool UseCustomMemoryAllocator(std::shared_ptr<ICustomAllocator> allocator,
93  armnn::Optional<std::string&> errMsg) override
94  {
95  IgnoreUnused(errMsg);
96  ARMNN_LOG(info) << "Using Custom Allocator for ClBackend";
97 
98  // Set flag to signal the backend to use a custom memory allocator
99  m_CustomAllocator = std::make_shared<ClBackendCustomAllocatorWrapper>(std::move(allocator));
100  m_UsingCustomAllocator = true;
101  return m_UsingCustomAllocator;
102  }
103 
104  // 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 
127  return std::make_unique<ClBackendCustomAllocatorMemoryRegion>(cl::Buffer(buffer),
128  hostMemPtr,
129  m_CustomAllocator->GetMemorySourceType());
130  }
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  }
162  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  }
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
197  };
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  }
214  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
225  ClBackendCustomAllocatorMemoryRegion(const cl::Buffer &buffer, void* hostMemPtr, armnn::MemorySource source)
226  : ICLMemoryRegion(buffer.getInfo<CL_MEM_SIZE>())
227  {
228  _mem = buffer;
229  m_HostMemPtr = hostMemPtr;
230  m_MemorySource = source;
231  }
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  }
246  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  {
253  _mapping = m_HostMemPtr;
254  return _mapping;
255  break;
258  // 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  }
266  }
267 
268  void unmap(cl::CommandQueue &q) override
269  {
271  switch (m_MemorySource)
272  {
274  _mapping = nullptr;
275  break;
278  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  }
285  }
286  private:
287  void* m_HostMemPtr = nullptr;
288  armnn::MemorySource m_MemorySource;
289  };
290 
291  std::shared_ptr<ClBackendCustomAllocatorWrapper> m_CustomAllocator;
293 };
294 
295 } // namespace armnn
void * map(cl::CommandQueue &q, bool blocking) override
Definition: ClBackend.hpp:239
ClBackend(std::shared_ptr< ICustomAllocator > allocator)
Definition: ClBackend.hpp:36
std::unique_ptr< IWorkloadFactory > IWorkloadFactoryPtr
std::vector< OptimizationPtr > Optimizations
~ClBackend()=default
std::vector< BackendOptions > ModelOptions
std::unique_ptr< arm_compute::IMemoryRegion > make_region(size_t size, size_t alignment) override
Definition: ClBackend.hpp:122
#define ARMNN_LOG(severity)
Definition: Logging.hpp:202
void unmap(cl::CommandQueue &q) override
Definition: ClBackend.hpp:268
std::shared_ptr< ClBackendCustomAllocatorWrapper > m_CustomAllocator
Definition: ClBackend.hpp:291
unsigned int MemorySourceFlags
Copyright (c) 2021 ARM Limited and Contributors.
std::unique_ptr< IMemoryManager > IMemoryManagerUniquePtr
void IgnoreUnused(Ts &&...)
IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override
Definition: ClBackend.cpp:50
void RegisterTensorHandleFactories(TensorHandleFactoryRegistry &registry) override
(Optional) Register TensorHandleFactories Either this method or CreateMemoryManager() and IWorkloadFa...
Definition: ClBackend.cpp:147
The SubgraphView class represents a subgraph of a Graph.
IBackendInternal::IBackendSpecificModelContextPtr CreateBackendSpecificModelContext(const ModelOptions &modelOptions) const override
Definition: ClBackend.cpp:200
std::unique_ptr< armnn::profiling::IBackendProfiling > IBackendProfilingPtr
BackendCapabilities GetCapabilities() const override
Returns a BackendCapability if the backend lists the capability The BackendCapability must then be in...
Definition: ClBackend.hpp:87
OptimizationViews OptimizeSubgraphView(const SubgraphView &subgraph, const ModelOptions &modelOptions) const override
Definition: ClBackend.cpp:224
std::shared_ptr< IBackendModelContext > IBackendSpecificModelContextPtr
std::shared_ptr< IMemoryManager > IMemoryManagerSharedPtr
IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions &) const override
Create the runtime context of the backend.
Definition: ClBackend.cpp:184
std::vector< ITensorHandleFactory::FactoryId > GetHandleFactoryPreferences() const override
(Optional) Returns a vector of supported TensorHandleFactory ids in preference order.
Definition: ClBackend.cpp:141
virtual bool UseCustomMemoryAllocator(std::shared_ptr< ICustomAllocator > allocator, armnn::Optional< std::string &> errMsg) override
Signals the backend to use a custom memory allocator provided by the user.
Definition: ClBackend.hpp:92
BackendOptions BackendCapabilities
IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr &memoryManager=nullptr) const override
Definition: ClBackend.cpp:59
const BackendCapabilities gpuAccCapabilities("GpuAcc", { {"NonConstWeights", false}, {"AsyncExecution", false}, {"ProtectedContentAllocation", true} })
std::shared_ptr< ILayerSupport > ILayerSupportSharedPtr
Struct for the users to pass backend specific options.
const BackendId & GetId() const override
Definition: ClBackend.hpp:44
IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override
Definition: ClBackend.cpp:206
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
MemorySource
Define the Memory Source to reduce copies.
Definition: Types.hpp:198
IBackendInternal::IBackendProfilingContextPtr CreateBackendProfilingContext(const IRuntime::CreationOptions &, IBackendProfilingPtr &backendProfiling) override
Create context specifically used for profiling interaction from backends.
Definition: ClBackend.cpp:189
bool m_UsingCustomAllocator
Definition: ClBackend.hpp:292
ClBackendCustomAllocatorMemoryRegion(const cl::Buffer &buffer, void *hostMemPtr, armnn::MemorySource source)
Definition: ClBackend.hpp:225
void * allocate(size_t size, size_t alignment) override
Definition: ClBackend.hpp:111
IBackendInternal::Optimizations GetOptimizations() const override
Definition: ClBackend.cpp:195
static const BackendId & GetIdStatic()
Definition: ClBackend.cpp:44
ClBackendCustomAllocatorWrapper(std::shared_ptr< ICustomAllocator > alloc)
Definition: ClBackend.hpp:108
std::shared_ptr< armnn::profiling::IBackendProfilingContext > IBackendProfilingContextPtr
This is the bridge between backend and backend profiling we&#39;ll keep it in the backend namespace...
std::unique_ptr< IBackendContext > IBackendContextPtr