Compute Library
 20.02.1
TensorAllocator.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2019 ARM Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
25 
30 #include "tests/CL/CLAccessor.h"
31 #include "tests/Globals.h"
33 #include "tests/framework/Macros.h"
36 
37 #include <memory>
38 #include <random>
39 
40 namespace arm_compute
41 {
42 namespace test
43 {
44 namespace validation
45 {
46 namespace
47 {
48 cl_mem import_malloc_memory_helper(void *ptr, size_t size)
49 {
50  const cl_import_properties_arm import_properties[] =
51  {
52  CL_IMPORT_TYPE_ARM,
53  CL_IMPORT_TYPE_HOST_ARM,
54  0
55  };
56 
57  cl_int err = CL_SUCCESS;
58  cl_mem buf = clImportMemoryARM(CLKernelLibrary::get().context().get(), CL_MEM_READ_WRITE, import_properties, ptr, size, &err);
59  ARM_COMPUTE_ASSERT(err == CL_SUCCESS);
60 
61  return buf;
62 }
63 } // namespace
64 
65 TEST_SUITE(CL)
66 TEST_SUITE(UNIT)
67 TEST_SUITE(TensorAllocator)
68 
69 /** Validates import memory interface when importing cl buffer objects */
70 TEST_CASE(ImportMemoryBuffer, framework::DatasetMode::ALL)
71 {
72  // Init tensor info
73  const TensorInfo info(TensorShape(24U, 16U, 3U), 1, DataType::F32);
74 
75  // Allocate memory buffer
76  const size_t total_size = info.total_size();
77  auto buf = cl::Buffer(CLScheduler::get().context(), CL_MEM_READ_WRITE, total_size);
78 
79  // Negative case : Import nullptr
80  CLTensor t1;
81  t1.allocator()->init(info);
84 
85  // Negative case : Import memory to a tensor that is memory managed
86  CLTensor t2;
87  MemoryGroup mg;
88  t2.allocator()->set_associated_memory_group(&mg);
89  ARM_COMPUTE_EXPECT(!bool(t2.allocator()->import_memory(buf)), framework::LogLevel::ERRORS);
90  ARM_COMPUTE_EXPECT(t2.info()->is_resizable(), framework::LogLevel::ERRORS);
91 
92  // Negative case : Invalid buffer size
93  CLTensor t3;
94  const TensorInfo info_neg(TensorShape(32U, 16U, 3U), 1, DataType::F32);
95  t3.allocator()->init(info_neg);
96  ARM_COMPUTE_EXPECT(!bool(t3.allocator()->import_memory(buf)), framework::LogLevel::ERRORS);
97  ARM_COMPUTE_EXPECT(t3.info()->is_resizable(), framework::LogLevel::ERRORS);
98 
99  // Positive case : Set raw pointer
100  CLTensor t4;
101  t4.allocator()->init(info);
102  ARM_COMPUTE_EXPECT(bool(t4.allocator()->import_memory(buf)), framework::LogLevel::ERRORS);
103  ARM_COMPUTE_EXPECT(!t4.info()->is_resizable(), framework::LogLevel::ERRORS);
104  ARM_COMPUTE_EXPECT(t4.cl_buffer().get() == buf.get(), framework::LogLevel::ERRORS);
105  t4.allocator()->free();
106  ARM_COMPUTE_EXPECT(t4.info()->is_resizable(), framework::LogLevel::ERRORS);
107  ARM_COMPUTE_EXPECT(t4.cl_buffer().get() != buf.get(), framework::LogLevel::ERRORS);
108 }
109 
110 /** Validates import memory interface when importing malloced memory */
112 {
113  // Check if import extension is supported
114  if(!device_supports_extension(CLKernelLibrary::get().get_device(), "cl_arm_import_memory_host"))
115  {
116  return;
117  }
118  else
119  {
121  const TensorShape shape = TensorShape(24U, 16U, 3U);
123 
124  // Create tensor
125  const TensorInfo info(shape, 1, data_type);
126  CLTensor tensor;
127  tensor.allocator()->init(info);
128 
129  // Create and configure activation function
130  CLActivationLayer act_func;
131  act_func.configure(&tensor, nullptr, act_info);
132 
133  // Allocate and import tensor
134  const size_t total_size_in_elems = tensor.info()->tensor_shape().total_size();
135  const size_t total_size_in_bytes = tensor.info()->total_size();
136  const size_t alignment = CLKernelLibrary::get().get_device().getInfo<CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE>();
137  size_t space = total_size_in_bytes + alignment;
138  auto raw_data = support::cpp14::make_unique<uint8_t[]>(space);
139 
140  void *aligned_ptr = raw_data.get();
141  support::cpp11::align(alignment, total_size_in_bytes, aligned_ptr, space);
142 
143  cl::Buffer wrapped_buffer(import_malloc_memory_helper(aligned_ptr, total_size_in_bytes));
144  ARM_COMPUTE_EXPECT(bool(tensor.allocator()->import_memory(wrapped_buffer)), framework::LogLevel::ERRORS);
146 
147  // Fill tensor
148  std::uniform_real_distribution<float> distribution(-5.f, 5.f);
149  std::mt19937 gen(library->seed());
150  auto *typed_ptr = reinterpret_cast<float *>(aligned_ptr);
151  for(unsigned int i = 0; i < total_size_in_elems; ++i)
152  {
153  typed_ptr[i] = distribution(gen);
154  }
155 
156  // Execute function and sync
157  act_func.run();
159 
160  // Validate result by checking that the input has no negative values
161  for(unsigned int i = 0; i < total_size_in_elems; ++i)
162  {
164  }
165 
166  // Release resources
167  tensor.allocator()->free();
169  }
170 }
171 
172 #if !defined(BARE_METAL)
173 /** Validates import memory interface when importing memory mapped objects */
174 TEST_CASE(ImportMemoryMappedFile, framework::DatasetMode::ALL)
175 {
176  // Check if import extension is supported
177  if(!device_supports_extension(CLKernelLibrary::get().get_device(), "cl_arm_import_memory_host"))
178  {
179  return;
180  }
181  else
182  {
184  const TensorShape shape = TensorShape(24U, 16U, 3U);
186 
187  // Create tensor
188  const TensorInfo info(shape, 1, data_type);
189  CLTensor tensor;
190  tensor.allocator()->init(info);
191 
192  // Create and configure activation function
193  CLActivationLayer act_func;
194  act_func.configure(&tensor, nullptr, act_info);
195 
196  // Get number of elements
197  const size_t total_size_in_elems = tensor.info()->tensor_shape().total_size();
198  const size_t total_size_in_bytes = tensor.info()->total_size();
199 
200  // Create file
201  std::ofstream output_file("test_mmap_import.bin", std::ios::binary | std::ios::out);
202  output_file.seekp(total_size_in_bytes - 1);
203  output_file.write("", 1);
204  output_file.close();
205 
206  // Map file
207  utils::mmap_io::MMappedFile mmapped_file("test_mmap_import.bin", 0 /** Whole file */, 0);
209  unsigned char *data = mmapped_file.data();
210 
211  cl::Buffer wrapped_buffer(import_malloc_memory_helper(data, total_size_in_bytes));
212  ARM_COMPUTE_EXPECT(bool(tensor.allocator()->import_memory(wrapped_buffer)), framework::LogLevel::ERRORS);
214 
215  // Fill tensor
216  std::uniform_real_distribution<float> distribution(-5.f, 5.f);
217  std::mt19937 gen(library->seed());
218  auto *typed_ptr = reinterpret_cast<float *>(data);
219  for(unsigned int i = 0; i < total_size_in_elems; ++i)
220  {
221  typed_ptr[i] = distribution(gen);
222  }
223 
224  // Execute function and sync
225  act_func.run();
227 
228  // Validate result by checking that the input has no negative values
229  for(unsigned int i = 0; i < total_size_in_elems; ++i)
230  {
232  }
233 
234  // Release resources
235  tensor.allocator()->free();
237  }
238 }
239 #endif // !defined(BARE_METAL)
240 
241 /** Validates symmetric per channel quantization */
242 TEST_CASE(Symm8PerChannelQuantizationInfo, framework::DatasetMode::ALL)
243 {
244  // Create tensor
245  CLTensor tensor;
246  const std::vector<float> scale = { 0.25f, 1.4f, 3.2f, 2.3f, 4.7f };
248  tensor.allocator()->init(info);
249 
250  // Check quantization information
255 
256  CLQuantization quantization = tensor.quantization();
257  ARM_COMPUTE_ASSERT(quantization.scale != nullptr);
258  ARM_COMPUTE_ASSERT(quantization.offset != nullptr);
259 
260  // Check OpenCL quantization arrays before allocating
261  ARM_COMPUTE_EXPECT(quantization.scale->max_num_values() == 0, framework::LogLevel::ERRORS);
262  ARM_COMPUTE_EXPECT(quantization.offset->max_num_values() == 0, framework::LogLevel::ERRORS);
263 
264  // Check OpenCL quantization arrays after allocating
265  tensor.allocator()->allocate();
266  ARM_COMPUTE_EXPECT(quantization.scale->max_num_values() == scale.size(), framework::LogLevel::ERRORS);
267  ARM_COMPUTE_EXPECT(quantization.offset->max_num_values() == 0, framework::LogLevel::ERRORS);
268 
269  // Validate that the scale values are the same
270  auto cl_scale_buffer = quantization.scale->cl_buffer();
271  void *mapped_ptr = CLScheduler::get().queue().enqueueMapBuffer(cl_scale_buffer, CL_TRUE, CL_MAP_READ, 0, scale.size());
272  auto cl_scale_ptr = static_cast<float *>(mapped_ptr);
273  for(unsigned int i = 0; i < scale.size(); ++i)
274  {
275  ARM_COMPUTE_EXPECT(cl_scale_ptr[i] == scale[i], framework::LogLevel::ERRORS);
276  }
277  CLScheduler::get().queue().enqueueUnmapMemObject(cl_scale_buffer, mapped_ptr);
278 }
279 
280 TEST_SUITE_END() // TensorAllocator
281 TEST_SUITE_END() // UNIT
282 TEST_SUITE_END() // CL
283 } // namespace validation
284 } // namespace test
285 } // namespace arm_compute
const std::vector< int32_t > & offset() const
Offset vector accessor.
Shape of a tensor.
Definition: TensorShape.h:39
cl::Device & get_device()
Gets the CL device for which the programs are created.
TensorInfo * info() const override
Interface to be implemented by the child class to return the tensor's metadata.
Definition: CLTensor.cpp:41
bool is_resizable() const override
Flag indicating whether the size of the tensor can be changed.
Definition: TensorInfo.h:285
static CLScheduler & get()
Access the scheduler singleton.
Definition: CLScheduler.cpp:99
QuantizationInfo quantization_info() const override
Get the quantization settings (scale and offset) of the tensor.
Definition: TensorInfo.h:311
1 channel, 1 F32 per channel
ARM_COMPUTE_EXPECT(has_error==expected, framework::LogLevel::ERRORS)
static CLKernelLibrary & get()
Access the KernelLibrary singleton.
CLTensorAllocator * allocator()
Return a pointer to the tensor's allocator.
Definition: CLTensor.cpp:61
Basic function to run CLActivationLayerKernel.
TEST_CASE(Configuration, framework::DatasetMode::ALL)
Activation Layer Information class.
Definition: Types.h:1615
OpenCL quantization data.
Definition: CLTypes.h:59
void init(const TensorInfo &input, size_t alignment=0)
Initialize a tensor based on the passed TensorInfo.
Copyright (c) 2017-2020 ARM Limited.
Status import_memory(cl::Buffer buffer)
Import an existing memory as a tensor's backing memory.
Quantization information.
DatasetMode
Possible dataset modes.
Definition: DatasetModes.h:40
std::unique_ptr< AssetsLibrary > library
Definition: main.cpp:77
void run() override final
Run the kernels contained in the function.
CLQuantization quantization() const override
Interface to be implemented by the child class to return the wrapped quantization info data.
Definition: CLTensor.cpp:56
size_t total_size() const override
Returns the total size of the tensor in bytes.
Definition: TensorInfo.h:273
size_t total_size() const
Collapses all dimensions to a single linear total size.
Definition: TensorShape.h:171
bool is_mapped() const
Checks if file mapped.
const std::vector< float > & scale() const
Scale vector accessor.
void * align(std::size_t alignment, std::size_t size, void *&ptr, std::size_t &space)
std::uniform_real_distribution< float > distribution(-5.f, 5.f)
cl::CommandQueue & queue()
Accessor for the associated CL command queue.
Definition: CLScheduler.cpp:41
unsigned char * data()
Mapped data accessor.
#define ARM_COMPUTE_ASSERT(X)
Definition: Asserts.h:110
void sync()
Blocks until all commands in the associated command queue have finished.
Definition: CLScheduler.cpp:67
quantized, symmetric per channel fixed-point 8-bit number
void allocate() override
Allocate size specified by TensorInfo of OpenCL memory.
bool device_supports_extension(const cl::Device &device, const char *extension_name)
Helper function to check whether a given extension is supported.
Definition: CLHelpers.cpp:282
bool empty() const
Indicates whether this QuantizationInfo has valid settings or not.
void free() override
Free allocated OpenCL memory.
TEST_SUITE_END() FIXTURE_DATA_TEST_CASE(RunSmall
Input data sets.
void configure(ICLTensor *input, ICLTensor *output, ActivationLayerInfo act_info)
Set the input and output tensor.
Store the tensor's metadata.
Definition: TensorInfo.h:45
cl_mem clImportMemoryARM(cl_context context, cl_mem_flags flags, const cl_import_properties_arm *properties, void *memory, size_t size, cl_int *errcode_ret)
Definition: OpenCL.cpp:933
const TensorShape & tensor_shape() const override
Size for each dimension of the tensor.
Definition: TensorInfo.h:261
DataType
Available data types.
Definition: Types.h:75
TEST_SUITE(U8_to_S8) DATA_TEST_CASE(Configuration
Basic implementation of the OpenCL tensor interface.
Definition: CLTensor.h:41