blob: 343168426c2f6fa4b2989ca84d5720c4a1d90675 [file] [log] [blame]
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +01001/*
2 * Copyright (c) 2017 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 */
24#include "Framework.h"
25
26#include "Exceptions.h"
27#include "support/ToolchainSupport.h"
28
Moritz Pflanzer47752c92017-07-18 13:38:47 +010029#ifdef ARM_COMPUTE_CL
30#include "arm_compute/core/CL/OpenCL.h"
Anthony Barbierbf959222017-07-19 17:01:42 +010031#include "arm_compute/runtime/CL/CLScheduler.h"
Moritz Pflanzer47752c92017-07-18 13:38:47 +010032#endif /* ARM_COMPUTE_CL */
33
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +010034#include <chrono>
35#include <iostream>
36#include <sstream>
37#include <type_traits>
38
39namespace arm_compute
40{
41namespace test
42{
43namespace framework
44{
Moritz Pflanzera4f711b2017-07-05 11:02:23 +010045Framework::Framework()
46{
47 _available_instruments.emplace(InstrumentType::WALL_CLOCK_TIMER, Instrument::make_instrument<WallClockTimer>);
48#ifdef PMU_ENABLED
49 _available_instruments.emplace(InstrumentType::PMU_CYCLE_COUNTER, Instrument::make_instrument<CycleCounter>);
50 _available_instruments.emplace(InstrumentType::PMU_INSTRUCTION_COUNTER, Instrument::make_instrument<InstructionCounter>);
51#endif /* PMU_ENABLED */
52}
53
54std::set<InstrumentType> Framework::available_instruments() const
55{
56 std::set<InstrumentType> types;
57
58 for(const auto &instrument : _available_instruments)
59 {
60 types.emplace(instrument.first);
61 }
62
63 return types;
64}
65
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +010066std::tuple<int, int, int> Framework::count_test_results() const
67{
68 int passed = 0;
69 int failed = 0;
70 int crashed = 0;
71
72 for(const auto &test : _test_results)
73 {
74 switch(test.second.status)
75 {
76 case TestResult::Status::SUCCESS:
77 ++passed;
78 break;
79 case TestResult::Status::FAILED:
80 ++failed;
81 break;
82 case TestResult::Status::CRASHED:
83 ++crashed;
84 break;
85 default:
86 // Do nothing
87 break;
88 }
89 }
90
91 return std::make_tuple(passed, failed, crashed);
92}
93
94Framework &Framework::get()
95{
96 static Framework instance;
97 return instance;
98}
99
Moritz Pflanzer81527bf2017-07-20 15:11:33 +0100100void Framework::init(const std::vector<InstrumentType> &instruments, int num_iterations, DatasetMode mode, const std::string &name_filter, int64_t id_filter)
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100101{
102 _test_name_filter = std::regex{ name_filter };
Moritz Pflanzer81527bf2017-07-20 15:11:33 +0100103 _test_id_filter = id_filter;
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100104 _num_iterations = num_iterations;
Moritz Pflanzerd03b00a2017-07-17 13:50:12 +0100105 _dataset_mode = mode;
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100106
107 _instruments = InstrumentType::NONE;
108
109 for(const auto &instrument : instruments)
110 {
111 _instruments |= instrument;
112 }
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100113}
114
115std::string Framework::current_suite_name() const
116{
117 return join(_test_suite_name.cbegin(), _test_suite_name.cend(), "/");
118}
119
120void Framework::push_suite(std::string name)
121{
122 _test_suite_name.emplace_back(std::move(name));
123}
124
125void Framework::pop_suite()
126{
127 _test_suite_name.pop_back();
128}
129
130void Framework::log_test_start(const std::string &test_name)
131{
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100132 if(_printer != nullptr)
133 {
134 _printer->print_test_header(test_name);
135 }
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100136}
137
138void Framework::log_test_skipped(const std::string &test_name)
139{
140 static_cast<void>(test_name);
141}
142
143void Framework::log_test_end(const std::string &test_name)
144{
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100145 if(_printer != nullptr)
146 {
147 _printer->print_measurements(_test_results.at(test_name).measurements);
148 _printer->print_test_footer();
149 }
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100150}
151
152void Framework::log_failed_expectation(const std::string &msg)
153{
154 std::cerr << "ERROR: " << msg << "\n";
Moritz Pflanzere1103a82017-07-18 12:20:45 +0100155
156 if(_current_test_result != nullptr)
157 {
158 _current_test_result->status = TestResult::Status::FAILED;
159 }
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100160}
161
162int Framework::num_iterations() const
163{
164 return _num_iterations;
165}
166
167void Framework::set_num_iterations(int num_iterations)
168{
169 _num_iterations = num_iterations;
170}
171
172void Framework::set_throw_errors(bool throw_errors)
173{
174 _throw_errors = throw_errors;
175}
176
177bool Framework::throw_errors() const
178{
179 return _throw_errors;
180}
181
182bool Framework::is_enabled(const TestId &id) const
183{
Moritz Pflanzerd03b00a2017-07-17 13:50:12 +0100184 int test_id = 0;
185 std::string name;
186 DatasetMode mode = DatasetMode::ALL;
187 std::tie(test_id, name, mode) = id;
188
189 if((mode & _dataset_mode) == DatasetMode::DISABLED)
190 {
191 return false;
192 }
193
Moritz Pflanzer81527bf2017-07-20 15:11:33 +0100194 if(_test_id_filter > -1 && _test_id_filter != test_id)
Moritz Pflanzerd03b00a2017-07-17 13:50:12 +0100195 {
196 return false;
197 }
198
199 if(!std::regex_search(name, _test_name_filter))
200 {
201 return false;
202 }
203
204 return true;
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100205}
206
207void Framework::run_test(TestCaseFactory &test_factory)
208{
209 const std::string test_case_name = test_factory.name();
210
211 log_test_start(test_case_name);
212
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100213 Profiler profiler = get_profiler();
Moritz Pflanzere1103a82017-07-18 12:20:45 +0100214 TestResult result(TestResult::Status::SUCCESS);
215
216 _current_test_result = &result;
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100217
218 try
219 {
220 std::unique_ptr<TestCase> test_case = test_factory.make();
221
222 try
223 {
224 test_case->do_setup();
225
226 for(int i = 0; i < _num_iterations; ++i)
227 {
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100228 profiler.start();
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100229 test_case->do_run();
Anthony Barbierbf959222017-07-19 17:01:42 +0100230#ifdef ARM_COMPUTE_CL
231 if(opencl_is_available())
232 {
233 CLScheduler::get().sync();
234 }
235#endif /* ARM_COMPUTE_CL */
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100236 profiler.stop();
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100237 }
238
239 test_case->do_teardown();
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100240 }
241 catch(const TestError &error)
242 {
243 std::cerr << "FATAL ERROR: " << error.what() << "\n";
244 result.status = TestResult::Status::FAILED;
245
246 if(_throw_errors)
247 {
248 throw;
249 }
250 }
Moritz Pflanzer47752c92017-07-18 13:38:47 +0100251#ifdef ARM_COMPUTE_CL
252 catch(const ::cl::Error &error)
253 {
254 std::cerr << "FATAL CL ERROR: " << error.what() << " with code " << error.err() << "\n";
255 result.status = TestResult::Status::FAILED;
256
257 if(_throw_errors)
258 {
259 throw;
260 }
261 }
262#endif /* ARM_COMPUTE_CL */
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100263 catch(const std::exception &error)
264 {
265 std::cerr << "FATAL ERROR: Received unhandled error: '" << error.what() << "'\n";
266 result.status = TestResult::Status::CRASHED;
267
268 if(_throw_errors)
269 {
270 throw;
271 }
272 }
273 catch(...)
274 {
275 std::cerr << "FATAL ERROR: Received unhandled exception\n";
276 result.status = TestResult::Status::CRASHED;
277
278 if(_throw_errors)
279 {
280 throw;
281 }
282 }
283 }
284 catch(const std::exception &error)
285 {
286 std::cerr << "FATAL ERROR: Received unhandled error during fixture creation: '" << error.what() << "'\n";
287
288 if(_throw_errors)
289 {
290 throw;
291 }
292 }
293 catch(...)
294 {
295 std::cerr << "FATAL ERROR: Received unhandled exception during fixture creation\n";
Moritz Pflanzere1103a82017-07-18 12:20:45 +0100296 result.status = TestResult::Status::CRASHED;
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100297
298 if(_throw_errors)
299 {
300 throw;
301 }
302 }
303
Moritz Pflanzere1103a82017-07-18 12:20:45 +0100304 _current_test_result = nullptr;
305
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100306 result.measurements = profiler.measurements();
307
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100308 set_test_result(test_case_name, result);
309 log_test_end(test_case_name);
310}
311
312bool Framework::run()
313{
314 // Clear old test results
315 _test_results.clear();
316 _runtime = std::chrono::seconds{ 0 };
317
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100318 if(_printer != nullptr)
319 {
320 _printer->print_run_header();
321 }
322
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100323 const auto start = std::chrono::high_resolution_clock::now();
324
325 int id = 0;
326
327 for(auto &test_factory : _test_factories)
328 {
329 const std::string test_case_name = test_factory->name();
330
Moritz Pflanzerd03b00a2017-07-17 13:50:12 +0100331 if(!is_enabled(TestId(id, test_case_name, test_factory->mode())))
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100332 {
333 log_test_skipped(test_case_name);
334 }
335 else
336 {
337 run_test(*test_factory);
338 }
339
340 ++id;
341 }
342
343 const auto end = std::chrono::high_resolution_clock::now();
344
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100345 if(_printer != nullptr)
346 {
347 _printer->print_run_footer();
348 }
349
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100350 _runtime = std::chrono::duration_cast<std::chrono::seconds>(end - start);
351
352 int passed = 0;
353 int failed = 0;
354 int crashed = 0;
355
356 std::tie(passed, failed, crashed) = count_test_results();
357
358 std::cout << "Executed " << _test_results.size() << " test(s) (" << passed << " passed, " << failed << " failed, " << crashed << " crashed) in " << _runtime.count() << " second(s)\n";
359
360 return (static_cast<unsigned int>(passed) == _test_results.size());
361}
362
363void Framework::set_test_result(std::string test_case_name, TestResult result)
364{
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100365 _test_results.emplace(std::move(test_case_name), std::move(result));
366}
367
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100368void Framework::print_test_results(Printer &printer) const
369{
370 printer.print_run_header();
371
372 for(const auto &test : _test_results)
373 {
374 printer.print_test_header(test.first);
375 printer.print_measurements(test.second.measurements);
376 printer.print_test_footer();
377 }
378
379 printer.print_run_footer();
380}
381
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100382Profiler Framework::get_profiler() const
383{
384 Profiler profiler;
385
386 for(const auto &instrument : _available_instruments)
387 {
388 if((instrument.first & _instruments) != InstrumentType::NONE)
389 {
390 profiler.add(instrument.second());
391 }
392 }
393
394 return profiler;
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100395}
396
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100397void Framework::set_printer(Printer *printer)
398{
399 _printer = printer;
400}
401
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100402std::vector<Framework::TestId> Framework::test_ids() const
403{
404 std::vector<TestId> ids;
405
406 int id = 0;
407
408 for(const auto &factory : _test_factories)
409 {
Moritz Pflanzerd03b00a2017-07-17 13:50:12 +0100410 if(is_enabled(TestId(id, factory->name(), factory->mode())))
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100411 {
Moritz Pflanzerd03b00a2017-07-17 13:50:12 +0100412 ids.emplace_back(id, factory->name(), factory->mode());
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100413 }
414
415 ++id;
416 }
417
418 return ids;
419}
420} // namespace framework
421} // namespace test
422} // namespace arm_compute