blob: b0e162accd66822046255fe49119b6686792416f [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Pablo Tellodb9116f2019-07-11 16:50:37 +01002 * Copyright (c) 2017-2019 ARM Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +01003 *
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 */
24#include "Utils.h"
25
Pablo Tellocf9c8432019-07-22 17:36:03 +010026#ifdef ARM_COMPUTE_CL
Pablo Tellodb9116f2019-07-11 16:50:37 +010027#include "arm_compute/runtime/CL/CLScheduler.h"
Pablo Tellocf9c8432019-07-22 17:36:03 +010028#endif /* ARM_COMPUTE_CL */
Pablo Tellodb9116f2019-07-11 16:50:37 +010029
Anthony Barbier6ff3b192017-09-04 18:44:23 +010030#include <cctype>
31#include <cerrno>
32#include <iomanip>
33#include <string>
34
Anthony Barbier1c28ab42018-08-29 11:22:33 +010035#pragma GCC diagnostic push
36#pragma GCC diagnostic ignored "-Wswitch-default"
Michalis Spyrou6bff1952019-10-02 17:22:11 +010037#pragma GCC diagnostic ignored "-Wunused-parameter"
Anthony Barbier1c28ab42018-08-29 11:22:33 +010038#define STB_IMAGE_IMPLEMENTATION
39#include "stb/stb_image.h"
40#pragma GCC diagnostic pop
41
Anthony Barbier6ff3b192017-09-04 18:44:23 +010042namespace arm_compute
43{
44namespace utils
45{
46namespace
47{
48/* Advance the iterator to the first character which is not a comment
49 *
50 * @param[in,out] fs Stream to drop comments from
51 */
52void discard_comments(std::ifstream &fs)
53{
54 while(fs.peek() == '#')
55 {
56 fs.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
57 }
58}
59
60/* Advance the string iterator to the next character which is neither a space or a comment
61 *
62 * @param[in,out] fs Stream to drop comments from
63 */
64void discard_comments_and_spaces(std::ifstream &fs)
65{
66 while(true)
67 {
68 discard_comments(fs);
69
70 if(isspace(fs.peek()) == 0)
71 {
72 break;
73 }
74
75 fs.ignore(1);
76 }
77}
78} // namespace
79
Anthony Barbier6db0ff52018-01-05 10:59:12 +000080#ifndef BENCHMARK_EXAMPLES
Anthony Barbier9fb0cac2018-04-20 15:46:21 +010081int run_example(int argc, char **argv, std::unique_ptr<Example> example)
Anthony Barbier6db0ff52018-01-05 10:59:12 +000082{
83 std::cout << "\n"
84 << argv[0] << "\n\n";
85
86 try
87 {
Georgios Pinitas12be7ab2018-07-03 12:06:23 +010088 bool status = example->do_setup(argc, argv);
89 if(!status)
90 {
91 return 1;
92 }
Anthony Barbier9fb0cac2018-04-20 15:46:21 +010093 example->do_run();
94 example->do_teardown();
Anthony Barbier6db0ff52018-01-05 10:59:12 +000095
96 std::cout << "\nTest passed\n";
97 return 0;
98 }
99#ifdef ARM_COMPUTE_CL
100 catch(cl::Error &err)
101 {
102 std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
103 std::cerr << std::endl
104 << "ERROR " << err.what() << "(" << err.err() << ")" << std::endl;
105 std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
106 }
107#endif /* ARM_COMPUTE_CL */
108 catch(std::runtime_error &err)
109 {
110 std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
111 std::cerr << std::endl
112 << "ERROR " << err.what() << " " << (errno ? strerror(errno) : "") << std::endl;
113 std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
114 }
115
116 std::cout << "\nTest FAILED\n";
117
118 return -1;
119}
120#endif /* BENCHMARK_EXAMPLES */
121
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100122void draw_detection_rectangle(ITensor *tensor, const DetectionWindow &rect, uint8_t r, uint8_t g, uint8_t b)
123{
124 ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(tensor, Format::RGB888);
125
126 uint8_t *top = tensor->info()->offset_element_in_bytes(Coordinates(rect.x, rect.y)) + tensor->buffer();
127 uint8_t *bottom = tensor->info()->offset_element_in_bytes(Coordinates(rect.x, rect.y + rect.height)) + tensor->buffer();
128 uint8_t *left = top;
129 uint8_t *right = tensor->info()->offset_element_in_bytes(Coordinates(rect.x + rect.width, rect.y)) + tensor->buffer();
130 size_t stride = tensor->info()->strides_in_bytes()[Window::DimY];
131
132 for(size_t x = 0; x < rect.width; ++x)
133 {
134 top[0] = r;
135 top[1] = g;
136 top[2] = b;
137 bottom[0] = r;
138 bottom[1] = g;
139 bottom[2] = b;
140
141 top += 3;
142 bottom += 3;
143 }
144
145 for(size_t y = 0; y < rect.height; ++y)
146 {
147 left[0] = r;
148 left[1] = g;
149 left[2] = b;
150 right[0] = r;
151 right[1] = g;
152 right[2] = b;
153
154 left += stride;
155 right += stride;
156 }
157}
158
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100159ImageType get_image_type_from_file(const std::string &filename)
160{
161 ImageType type = ImageType::UNKNOWN;
162
163 try
164 {
165 // Open file
166 std::ifstream fs;
167 fs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
168 fs.open(filename, std::ios::in | std::ios::binary);
169
170 // Identify type from magic number
171 std::array<unsigned char, 2> magic_number{ { 0 } };
172 fs >> magic_number[0] >> magic_number[1];
173
174 // PPM check
175 if(static_cast<char>(magic_number[0]) == 'P' && static_cast<char>(magic_number[1]) == '6')
176 {
177 type = ImageType::PPM;
178 }
179 else if(magic_number[0] == 0xFF && magic_number[1] == 0xD8)
180 {
181 type = ImageType::JPEG;
182 }
183
184 fs.close();
185 }
186 catch(std::runtime_error &e)
187 {
188 ARM_COMPUTE_ERROR("Accessing %s: %s", filename.c_str(), e.what());
189 }
190
191 return type;
192}
193
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100194std::tuple<unsigned int, unsigned int, int> parse_ppm_header(std::ifstream &fs)
195{
196 // Check the PPM magic number is valid
197 std::array<char, 2> magic_number{ { 0 } };
198 fs >> magic_number[0] >> magic_number[1];
199 ARM_COMPUTE_ERROR_ON_MSG(magic_number[0] != 'P' || magic_number[1] != '6', "Invalid file type");
200 ARM_COMPUTE_UNUSED(magic_number);
201
202 discard_comments_and_spaces(fs);
203
204 unsigned int width = 0;
205 fs >> width;
206
207 discard_comments_and_spaces(fs);
208
209 unsigned int height = 0;
210 fs >> height;
211
212 discard_comments_and_spaces(fs);
213
214 int max_val = 0;
215 fs >> max_val;
216
217 discard_comments(fs);
218
219 ARM_COMPUTE_ERROR_ON_MSG(isspace(fs.peek()) == 0, "Invalid PPM header");
220 fs.ignore(1);
221
222 return std::make_tuple(width, height, max_val);
223}
Giorgio Arenacf3935f2017-10-26 17:14:13 +0100224
225std::tuple<std::vector<unsigned long>, bool, std::string> parse_npy_header(std::ifstream &fs) //NOLINT
226{
227 std::vector<unsigned long> shape; // NOLINT
228
Giorgio Arenacf3935f2017-10-26 17:14:13 +0100229 // Read header
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000230 std::string header = npy::read_header(fs);
Giorgio Arenacf3935f2017-10-26 17:14:13 +0100231
232 // Parse header
233 bool fortran_order = false;
234 std::string typestr;
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000235 npy::parse_header(header, typestr, fortran_order, shape);
Giorgio Arenacf3935f2017-10-26 17:14:13 +0100236
Michalis Spyrou39412952018-08-14 17:06:16 +0100237 std::reverse(shape.begin(), shape.end());
Giorgio Arenacf3935f2017-10-26 17:14:13 +0100238
239 return std::make_tuple(shape, fortran_order, typestr);
240}
Gian Marco5ca74092018-02-08 16:21:54 +0000241
242/** This function returns the amount of memory free reading from /proc/meminfo
243 *
244 * @return The free memory in kB
245 */
246uint64_t get_mem_free_from_meminfo()
247{
248 std::string line_attribute;
249 std::ifstream file_meminfo("/proc/meminfo");
250
251 if(file_meminfo.is_open())
252 {
253 while(!(file_meminfo >> line_attribute).fail())
254 {
255 //Test if is the line containing MemFree
256 if(line_attribute == "MemFree:")
257 {
258 uint64_t mem_available;
259 if(!(file_meminfo >> mem_available).fail())
260 {
261 return mem_available;
262 }
263 else
264 {
265 return 0;
266 }
267 }
268 // if it's not MemFree ignore rest of the line
269 file_meminfo.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
270 }
271 }
272 // Nothing found or an error during opening the file
273 return 0;
274}
Pablo Tellodb9116f2019-07-11 16:50:37 +0100275
276/** This function loads prebuilt opencl kernels from a file
277 *
278 * @param[in] filename Name of the file to be used to load the kernels
279 */
280void restore_program_cache_from_file(const std::string &filename)
281{
Pablo Tellocf9c8432019-07-22 17:36:03 +0100282#ifdef ARM_COMPUTE_CL
Pablo Tellodb9116f2019-07-11 16:50:37 +0100283 std::ifstream cache_file(filename, std::ios::binary);
284 if(cache_file.is_open())
285 {
286 if(!CLScheduler::get().is_initialised())
287 {
288 arm_compute::CLScheduler::get().default_init();
289 }
290
291 while(!cache_file.eof())
292 {
293 size_t name_len = 0;
294 size_t binary_len = 0;
295 cache_file.read(reinterpret_cast<char *>(&name_len), sizeof(size_t));
296 cache_file.read(reinterpret_cast<char *>(&binary_len), sizeof(size_t));
297 if(name_len == 0 || binary_len == 0)
298 {
299 break;
300 }
301 std::vector<char> tmp(name_len);
302 std::vector<unsigned char> binary(binary_len);
303 std::string name;
304 cache_file.read(tmp.data(), name_len);
305 name.assign(tmp.data(), name_len);
306 tmp.resize(binary_len);
307 cache_file.read(reinterpret_cast<char *>(binary.data()), binary_len);
308 cl::Context context = arm_compute::CLScheduler::get().context();
309 cl::Program::Binaries binaries{ binary };
310 std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
311 cl::Program program(context, devices, binaries);
312 program.build();
313 CLKernelLibrary::get().add_built_program(name, program);
314 }
315 cache_file.close();
316 }
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100317#else /* ARM_COMPUTE_CL */
318 ARM_COMPUTE_UNUSED(filename);
Pablo Tellocf9c8432019-07-22 17:36:03 +0100319#endif /* ARM_COMPUTE_CL */
Pablo Tellodb9116f2019-07-11 16:50:37 +0100320}
321
322/** This function saves opencl kernels library to a file
323 *
324 * @param[in] filename Name of the file to be used to save the library
325 */
326void save_program_cache_to_file(const std::string &filename)
327{
Pablo Tellocf9c8432019-07-22 17:36:03 +0100328#ifdef ARM_COMPUTE_CL
Pablo Tellodb9116f2019-07-11 16:50:37 +0100329 if(CLScheduler::get().is_initialised())
330 {
331 std::ofstream cache_file(filename, std::ios::binary);
332 if(cache_file.is_open())
333 {
334 for(const auto &it : CLKernelLibrary::get().get_built_programs())
335 {
336 std::vector<std::vector<unsigned char>> binaries = it.second.getInfo<CL_PROGRAM_BINARIES>();
337 ARM_COMPUTE_ERROR_ON(binaries.size() != 1);
338 const std::string kernel_name = it.first;
339 size_t kernel_name_size = kernel_name.length();
340 size_t binary_size = binaries[0].size();
341 cache_file.write(reinterpret_cast<char *>(&kernel_name_size), sizeof(size_t));
342 cache_file.write(reinterpret_cast<char *>(&binary_size), sizeof(size_t));
343 cache_file.write(kernel_name.c_str(), kernel_name_size);
344 cache_file.write(reinterpret_cast<const char *>(binaries[0].data()), binaries[0].size());
345 }
346 cache_file.close();
347 }
348 else
349 {
350 ARM_COMPUTE_ERROR("Cannot open cache file");
351 }
352 }
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100353#else /* ARM_COMPUTE_CL */
354 ARM_COMPUTE_UNUSED(filename);
Pablo Tellocf9c8432019-07-22 17:36:03 +0100355#endif /* ARM_COMPUTE_CL */
Pablo Tellodb9116f2019-07-11 16:50:37 +0100356}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100357} // namespace utils
358} // namespace arm_compute