Compute Library
 20.05
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
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:1517
OpenCL quantization data.
Definition: CLTypes.h:62
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:78
void run() override final
Run the kernels contained in the function.
TEST_SUITE_END() FIXTURE_DATA_TEST_CASE(RunSmall
[CLActivationLayer Test snippet]
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)
Definition: MemorySupport.h:37
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.
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:941
SimpleTensor< T > scale(const SimpleTensor< T > &src, float scale_x, float scale_y, InterpolationPolicy policy, BorderMode border_mode, T constant_border_value, SamplingPolicy sampling_policy, bool ceil_policy_scale, bool align_corners)
Definition: Scale.cpp:187
const TensorShape & tensor_shape() const override
Size for each dimension of the tensor.
Definition: TensorInfo.h:261
DataType
Available data types.
Definition: Types.h:77
TEST_SUITE(U8_to_S8) DATA_TEST_CASE(Configuration
const cl::Device & get_device()
Gets the CL device for which the programs are created.
Basic implementation of the OpenCL tensor interface.
Definition: CLTensor.h:41