blob: 72fa1981fcc12c4cb4963cba1c55a5eef5b48ca3 [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
29#include <chrono>
30#include <iostream>
31#include <sstream>
32#include <type_traits>
33
34namespace arm_compute
35{
36namespace test
37{
38namespace framework
39{
Moritz Pflanzera4f711b2017-07-05 11:02:23 +010040Framework::Framework()
41{
42 _available_instruments.emplace(InstrumentType::WALL_CLOCK_TIMER, Instrument::make_instrument<WallClockTimer>);
43#ifdef PMU_ENABLED
44 _available_instruments.emplace(InstrumentType::PMU_CYCLE_COUNTER, Instrument::make_instrument<CycleCounter>);
45 _available_instruments.emplace(InstrumentType::PMU_INSTRUCTION_COUNTER, Instrument::make_instrument<InstructionCounter>);
46#endif /* PMU_ENABLED */
47}
48
49std::set<InstrumentType> Framework::available_instruments() const
50{
51 std::set<InstrumentType> types;
52
53 for(const auto &instrument : _available_instruments)
54 {
55 types.emplace(instrument.first);
56 }
57
58 return types;
59}
60
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +010061std::tuple<int, int, int> Framework::count_test_results() const
62{
63 int passed = 0;
64 int failed = 0;
65 int crashed = 0;
66
67 for(const auto &test : _test_results)
68 {
69 switch(test.second.status)
70 {
71 case TestResult::Status::SUCCESS:
72 ++passed;
73 break;
74 case TestResult::Status::FAILED:
75 ++failed;
76 break;
77 case TestResult::Status::CRASHED:
78 ++crashed;
79 break;
80 default:
81 // Do nothing
82 break;
83 }
84 }
85
86 return std::make_tuple(passed, failed, crashed);
87}
88
89Framework &Framework::get()
90{
91 static Framework instance;
92 return instance;
93}
94
Moritz Pflanzera4f711b2017-07-05 11:02:23 +010095void Framework::init(const std::vector<InstrumentType> &instruments, int num_iterations, const std::string &name_filter, const std::string &id_filter)
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +010096{
97 _test_name_filter = std::regex{ name_filter };
98 _test_id_filter = std::regex{ id_filter };
99 _num_iterations = num_iterations;
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100100
101 _instruments = InstrumentType::NONE;
102
103 for(const auto &instrument : instruments)
104 {
105 _instruments |= instrument;
106 }
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100107}
108
109std::string Framework::current_suite_name() const
110{
111 return join(_test_suite_name.cbegin(), _test_suite_name.cend(), "/");
112}
113
114void Framework::push_suite(std::string name)
115{
116 _test_suite_name.emplace_back(std::move(name));
117}
118
119void Framework::pop_suite()
120{
121 _test_suite_name.pop_back();
122}
123
124void Framework::log_test_start(const std::string &test_name)
125{
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100126 if(_printer != nullptr)
127 {
128 _printer->print_test_header(test_name);
129 }
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100130}
131
132void Framework::log_test_skipped(const std::string &test_name)
133{
134 static_cast<void>(test_name);
135}
136
137void Framework::log_test_end(const std::string &test_name)
138{
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100139 if(_printer != nullptr)
140 {
141 _printer->print_measurements(_test_results.at(test_name).measurements);
142 _printer->print_test_footer();
143 }
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100144}
145
146void Framework::log_failed_expectation(const std::string &msg)
147{
148 std::cerr << "ERROR: " << msg << "\n";
149}
150
151int Framework::num_iterations() const
152{
153 return _num_iterations;
154}
155
156void Framework::set_num_iterations(int num_iterations)
157{
158 _num_iterations = num_iterations;
159}
160
161void Framework::set_throw_errors(bool throw_errors)
162{
163 _throw_errors = throw_errors;
164}
165
166bool Framework::throw_errors() const
167{
168 return _throw_errors;
169}
170
171bool Framework::is_enabled(const TestId &id) const
172{
173 return (std::regex_search(support::cpp11::to_string(id.first), _test_id_filter) && std::regex_search(id.second, _test_name_filter));
174}
175
176void Framework::run_test(TestCaseFactory &test_factory)
177{
178 const std::string test_case_name = test_factory.name();
179
180 log_test_start(test_case_name);
181
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100182 Profiler profiler = get_profiler();
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100183 TestResult result;
184
185 try
186 {
187 std::unique_ptr<TestCase> test_case = test_factory.make();
188
189 try
190 {
191 test_case->do_setup();
192
193 for(int i = 0; i < _num_iterations; ++i)
194 {
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100195 profiler.start();
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100196 test_case->do_run();
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100197 profiler.stop();
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100198 }
199
200 test_case->do_teardown();
201
202 result.status = TestResult::Status::SUCCESS;
203 }
204 catch(const TestError &error)
205 {
206 std::cerr << "FATAL ERROR: " << error.what() << "\n";
207 result.status = TestResult::Status::FAILED;
208
209 if(_throw_errors)
210 {
211 throw;
212 }
213 }
214 catch(const std::exception &error)
215 {
216 std::cerr << "FATAL ERROR: Received unhandled error: '" << error.what() << "'\n";
217 result.status = TestResult::Status::CRASHED;
218
219 if(_throw_errors)
220 {
221 throw;
222 }
223 }
224 catch(...)
225 {
226 std::cerr << "FATAL ERROR: Received unhandled exception\n";
227 result.status = TestResult::Status::CRASHED;
228
229 if(_throw_errors)
230 {
231 throw;
232 }
233 }
234 }
235 catch(const std::exception &error)
236 {
237 std::cerr << "FATAL ERROR: Received unhandled error during fixture creation: '" << error.what() << "'\n";
238
239 if(_throw_errors)
240 {
241 throw;
242 }
243 }
244 catch(...)
245 {
246 std::cerr << "FATAL ERROR: Received unhandled exception during fixture creation\n";
247
248 if(_throw_errors)
249 {
250 throw;
251 }
252 }
253
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100254 result.measurements = profiler.measurements();
255
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100256 set_test_result(test_case_name, result);
257 log_test_end(test_case_name);
258}
259
260bool Framework::run()
261{
262 // Clear old test results
263 _test_results.clear();
264 _runtime = std::chrono::seconds{ 0 };
265
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100266 if(_printer != nullptr)
267 {
268 _printer->print_run_header();
269 }
270
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100271 const auto start = std::chrono::high_resolution_clock::now();
272
273 int id = 0;
274
275 for(auto &test_factory : _test_factories)
276 {
277 const std::string test_case_name = test_factory->name();
278
279 if(!is_enabled(TestId(id, test_case_name)))
280 {
281 log_test_skipped(test_case_name);
282 }
283 else
284 {
285 run_test(*test_factory);
286 }
287
288 ++id;
289 }
290
291 const auto end = std::chrono::high_resolution_clock::now();
292
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100293 if(_printer != nullptr)
294 {
295 _printer->print_run_footer();
296 }
297
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100298 _runtime = std::chrono::duration_cast<std::chrono::seconds>(end - start);
299
300 int passed = 0;
301 int failed = 0;
302 int crashed = 0;
303
304 std::tie(passed, failed, crashed) = count_test_results();
305
306 std::cout << "Executed " << _test_results.size() << " test(s) (" << passed << " passed, " << failed << " failed, " << crashed << " crashed) in " << _runtime.count() << " second(s)\n";
307
308 return (static_cast<unsigned int>(passed) == _test_results.size());
309}
310
311void Framework::set_test_result(std::string test_case_name, TestResult result)
312{
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100313 _test_results.emplace(std::move(test_case_name), std::move(result));
314}
315
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100316void Framework::print_test_results(Printer &printer) const
317{
318 printer.print_run_header();
319
320 for(const auto &test : _test_results)
321 {
322 printer.print_test_header(test.first);
323 printer.print_measurements(test.second.measurements);
324 printer.print_test_footer();
325 }
326
327 printer.print_run_footer();
328}
329
Moritz Pflanzera4f711b2017-07-05 11:02:23 +0100330Profiler Framework::get_profiler() const
331{
332 Profiler profiler;
333
334 for(const auto &instrument : _available_instruments)
335 {
336 if((instrument.first & _instruments) != InstrumentType::NONE)
337 {
338 profiler.add(instrument.second());
339 }
340 }
341
342 return profiler;
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100343}
344
Moritz Pflanzer80fffae2017-07-05 11:02:37 +0100345void Framework::set_printer(Printer *printer)
346{
347 _printer = printer;
348}
349
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +0100350std::vector<Framework::TestId> Framework::test_ids() const
351{
352 std::vector<TestId> ids;
353
354 int id = 0;
355
356 for(const auto &factory : _test_factories)
357 {
358 if(is_enabled(TestId(id, factory->name())))
359 {
360 ids.emplace_back(id, factory->name());
361 }
362
363 ++id;
364 }
365
366 return ids;
367}
368} // namespace framework
369} // namespace test
370} // namespace arm_compute