1*c217d954SCole Faust/// 2*c217d954SCole Faust/// Copyright (c) 2017-2021 Arm Limited. 3*c217d954SCole Faust/// 4*c217d954SCole Faust/// SPDX-License-Identifier: MIT 5*c217d954SCole Faust/// 6*c217d954SCole Faust/// Permission is hereby granted, free of charge, to any person obtaining a copy 7*c217d954SCole Faust/// of this software and associated documentation files (the "Software"), to 8*c217d954SCole Faust/// deal in the Software without restriction, including without limitation the 9*c217d954SCole Faust/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10*c217d954SCole Faust/// sell copies of the Software, and to permit persons to whom the Software is 11*c217d954SCole Faust/// furnished to do so, subject to the following conditions: 12*c217d954SCole Faust/// 13*c217d954SCole Faust/// The above copyright notice and this permission notice shall be included in all 14*c217d954SCole Faust/// copies or substantial portions of the Software. 15*c217d954SCole Faust/// 16*c217d954SCole Faust/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17*c217d954SCole Faust/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18*c217d954SCole Faust/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19*c217d954SCole Faust/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20*c217d954SCole Faust/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21*c217d954SCole Faust/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22*c217d954SCole Faust/// SOFTWARE. 23*c217d954SCole Faust/// 24*c217d954SCole Faustnamespace arm_compute 25*c217d954SCole Faust{ 26*c217d954SCole Faustnamespace test 27*c217d954SCole Faust{ 28*c217d954SCole Faust/** 29*c217d954SCole Faust@page tests Validation and Benchmarks 30*c217d954SCole Faust 31*c217d954SCole Faust@tableofcontents 32*c217d954SCole Faust 33*c217d954SCole Faust@section tests_overview Overview 34*c217d954SCole Faust 35*c217d954SCole FaustBenchmark and validation tests are based on the same framework to setup and run 36*c217d954SCole Faustthe tests. In addition to running simple, self-contained test functions the 37*c217d954SCole Faustframework supports fixtures and data test cases. The former allows to share 38*c217d954SCole Faustcommon setup routines between various backends thus reducing the amount of 39*c217d954SCole Faustduplicated code. The latter can be used to parameterize tests or fixtures with 40*c217d954SCole Faustdifferent inputs, e.g. different tensor shapes. One limitation is that 41*c217d954SCole Fausttests/fixtures cannot be parameterized based on the data type if static type 42*c217d954SCole Faustinformation is needed within the test (e.g. to validate the results). 43*c217d954SCole Faust 44*c217d954SCole Faust@note By default tests are not built. To enable them you need to add validation_tests=1 and / or benchmark_tests=1 to your SCons line. 45*c217d954SCole Faust 46*c217d954SCole Faust@note Tests are not included in the pre-built binary archive, you have to build them from sources. 47*c217d954SCole Faust 48*c217d954SCole Faust@subsection tests_overview_fixtures Fixtures 49*c217d954SCole Faust 50*c217d954SCole FaustFixtures can be used to share common setup, teardown or even run tasks among 51*c217d954SCole Faustmultiple test cases. For that purpose a fixture can define a `setup`, 52*c217d954SCole Faust`teardown` and `run` method. Additionally the constructor and destructor might 53*c217d954SCole Faustalso be customized. 54*c217d954SCole Faust 55*c217d954SCole FaustAn instance of the fixture is created immediately before the actual test is 56*c217d954SCole Faustexecuted. After construction the @ref framework::Fixture::setup method is called. Then the test 57*c217d954SCole Faustfunction or the fixtures `run` method is invoked. After test execution the 58*c217d954SCole Faust@ref framework::Fixture::teardown method is called and lastly the fixture is destructed. 59*c217d954SCole Faust 60*c217d954SCole Faust@subsubsection tests_overview_fixtures_fixture Fixture 61*c217d954SCole Faust 62*c217d954SCole FaustFixtures for non-parameterized test are straightforward. The custom fixture 63*c217d954SCole Faustclass has to inherit from @ref framework::Fixture and choose to implement any of the 64*c217d954SCole Faust`setup`, `teardown` or `run` methods. None of the methods takes any arguments 65*c217d954SCole Faustor returns anything. 66*c217d954SCole Faust 67*c217d954SCole Faust class CustomFixture : public framework::Fixture 68*c217d954SCole Faust { 69*c217d954SCole Faust void setup() 70*c217d954SCole Faust { 71*c217d954SCole Faust _ptr = malloc(4000); 72*c217d954SCole Faust } 73*c217d954SCole Faust 74*c217d954SCole Faust void run() 75*c217d954SCole Faust { 76*c217d954SCole Faust ARM_COMPUTE_ASSERT(_ptr != nullptr); 77*c217d954SCole Faust } 78*c217d954SCole Faust 79*c217d954SCole Faust void teardown() 80*c217d954SCole Faust { 81*c217d954SCole Faust free(_ptr); 82*c217d954SCole Faust } 83*c217d954SCole Faust 84*c217d954SCole Faust void *_ptr; 85*c217d954SCole Faust }; 86*c217d954SCole Faust 87*c217d954SCole Faust@subsubsection tests_overview_fixtures_data_fixture Data fixture 88*c217d954SCole Faust 89*c217d954SCole FaustThe advantage of a parameterized fixture is that arguments can be passed to the setup method at runtime. To make this possible the setup method has to be a template with a type parameter for every argument (though the template parameter doesn't have to be used). All other methods remain the same. 90*c217d954SCole Faust 91*c217d954SCole Faust class CustomFixture : public framework::Fixture 92*c217d954SCole Faust { 93*c217d954SCole Faust #ifdef ALTERNATIVE_DECLARATION 94*c217d954SCole Faust template <typename ...> 95*c217d954SCole Faust void setup(size_t size) 96*c217d954SCole Faust { 97*c217d954SCole Faust _ptr = malloc(size); 98*c217d954SCole Faust } 99*c217d954SCole Faust #else 100*c217d954SCole Faust template <typename T> 101*c217d954SCole Faust void setup(T size) 102*c217d954SCole Faust { 103*c217d954SCole Faust _ptr = malloc(size); 104*c217d954SCole Faust } 105*c217d954SCole Faust #endif 106*c217d954SCole Faust 107*c217d954SCole Faust void run() 108*c217d954SCole Faust { 109*c217d954SCole Faust ARM_COMPUTE_ASSERT(_ptr != nullptr); 110*c217d954SCole Faust } 111*c217d954SCole Faust 112*c217d954SCole Faust void teardown() 113*c217d954SCole Faust { 114*c217d954SCole Faust free(_ptr); 115*c217d954SCole Faust } 116*c217d954SCole Faust 117*c217d954SCole Faust void *_ptr; 118*c217d954SCole Faust }; 119*c217d954SCole Faust 120*c217d954SCole Faust@subsection tests_overview_test_cases Test cases 121*c217d954SCole Faust 122*c217d954SCole FaustAll following commands can be optionally prefixed with `EXPECTED_FAILURE_` or 123*c217d954SCole Faust`DISABLED_`. 124*c217d954SCole Faust 125*c217d954SCole Faust@subsubsection tests_overview_test_cases_test_case Test case 126*c217d954SCole Faust 127*c217d954SCole FaustA simple test case function taking no inputs and having no (shared) state. 128*c217d954SCole Faust 129*c217d954SCole Faust- First argument is the name of the test case (has to be unique within the 130*c217d954SCole Faust enclosing test suite). 131*c217d954SCole Faust- Second argument is the dataset mode in which the test will be active. 132*c217d954SCole Faust 133*c217d954SCole Faust 134*c217d954SCole Faust TEST_CASE(TestCaseName, DatasetMode::PRECOMMIT) 135*c217d954SCole Faust { 136*c217d954SCole Faust ARM_COMPUTE_ASSERT_EQUAL(1 + 1, 2); 137*c217d954SCole Faust } 138*c217d954SCole Faust 139*c217d954SCole Faust@subsubsection tests_overview_test_cases_fixture_fixture_test_case Fixture test case 140*c217d954SCole Faust 141*c217d954SCole FaustA simple test case function taking no inputs that inherits from a fixture. The 142*c217d954SCole Fausttest case will have access to all public and protected members of the fixture. 143*c217d954SCole FaustOnly the setup and teardown methods of the fixture will be used. The body of 144*c217d954SCole Faustthis function will be used as test function. 145*c217d954SCole Faust 146*c217d954SCole Faust- First argument is the name of the test case (has to be unique within the 147*c217d954SCole Faust enclosing test suite). 148*c217d954SCole Faust- Second argument is the class name of the fixture. 149*c217d954SCole Faust- Third argument is the dataset mode in which the test will be active. 150*c217d954SCole Faust 151*c217d954SCole Faust 152*c217d954SCole Faust class FixtureName : public framework::Fixture 153*c217d954SCole Faust { 154*c217d954SCole Faust public: 155*c217d954SCole Faust void setup() override 156*c217d954SCole Faust { 157*c217d954SCole Faust _one = 1; 158*c217d954SCole Faust } 159*c217d954SCole Faust 160*c217d954SCole Faust protected: 161*c217d954SCole Faust int _one; 162*c217d954SCole Faust }; 163*c217d954SCole Faust 164*c217d954SCole Faust FIXTURE_TEST_CASE(TestCaseName, FixtureName, DatasetMode::PRECOMMIT) 165*c217d954SCole Faust { 166*c217d954SCole Faust ARM_COMPUTE_ASSERT_EQUAL(_one + 1, 2); 167*c217d954SCole Faust } 168*c217d954SCole Faust 169*c217d954SCole Faust@subsubsection tests_overview_test_cases_fixture_register_fixture_test_case Registering a fixture as test case 170*c217d954SCole Faust 171*c217d954SCole FaustAllows to use a fixture directly as test case. Instead of defining a new test 172*c217d954SCole Faustfunction the run method of the fixture will be executed. 173*c217d954SCole Faust 174*c217d954SCole Faust- First argument is the name of the test case (has to be unique within the 175*c217d954SCole Faust enclosing test suite). 176*c217d954SCole Faust- Second argument is the class name of the fixture. 177*c217d954SCole Faust- Third argument is the dataset mode in which the test will be active. 178*c217d954SCole Faust 179*c217d954SCole Faust 180*c217d954SCole Faust class FixtureName : public framework::Fixture 181*c217d954SCole Faust { 182*c217d954SCole Faust public: 183*c217d954SCole Faust void setup() override 184*c217d954SCole Faust { 185*c217d954SCole Faust _one = 1; 186*c217d954SCole Faust } 187*c217d954SCole Faust 188*c217d954SCole Faust void run() override 189*c217d954SCole Faust { 190*c217d954SCole Faust ARM_COMPUTE_ASSERT_EQUAL(_one + 1, 2); 191*c217d954SCole Faust } 192*c217d954SCole Faust 193*c217d954SCole Faust protected: 194*c217d954SCole Faust int _one; 195*c217d954SCole Faust }; 196*c217d954SCole Faust 197*c217d954SCole Faust REGISTER_FIXTURE_TEST_CASE(TestCaseName, FixtureName, DatasetMode::PRECOMMIT); 198*c217d954SCole Faust 199*c217d954SCole Faust 200*c217d954SCole Faust@subsubsection tests_overview_test_cases_data_test_case Data test case 201*c217d954SCole Faust 202*c217d954SCole FaustA parameterized test case function that has no (shared) state. The dataset will 203*c217d954SCole Faustbe used to generate versions of the test case with different inputs. 204*c217d954SCole Faust 205*c217d954SCole Faust- First argument is the name of the test case (has to be unique within the 206*c217d954SCole Faust enclosing test suite). 207*c217d954SCole Faust- Second argument is the dataset mode in which the test will be active. 208*c217d954SCole Faust- Third argument is the dataset. 209*c217d954SCole Faust- Further arguments specify names of the arguments to the test function. The 210*c217d954SCole Faust number must match the arity of the dataset. 211*c217d954SCole Faust 212*c217d954SCole Faust 213*c217d954SCole Faust DATA_TEST_CASE(TestCaseName, DatasetMode::PRECOMMIT, framework::make("Numbers", {1, 2, 3}), num) 214*c217d954SCole Faust { 215*c217d954SCole Faust ARM_COMPUTE_ASSERT(num < 4); 216*c217d954SCole Faust } 217*c217d954SCole Faust 218*c217d954SCole Faust@subsubsection tests_overview_test_cases_fixture_data_test_case Fixture data test case 219*c217d954SCole Faust 220*c217d954SCole FaustA parameterized test case that inherits from a fixture. The test case will have 221*c217d954SCole Faustaccess to all public and protected members of the fixture. Only the setup and 222*c217d954SCole Faustteardown methods of the fixture will be used. The setup method of the fixture 223*c217d954SCole Faustneeds to be a template and has to accept inputs from the dataset as arguments. 224*c217d954SCole FaustThe body of this function will be used as test function. The dataset will be 225*c217d954SCole Faustused to generate versions of the test case with different inputs. 226*c217d954SCole Faust 227*c217d954SCole Faust- First argument is the name of the test case (has to be unique within the 228*c217d954SCole Faust enclosing test suite). 229*c217d954SCole Faust- Second argument is the class name of the fixture. 230*c217d954SCole Faust- Third argument is the dataset mode in which the test will be active. 231*c217d954SCole Faust- Fourth argument is the dataset. 232*c217d954SCole Faust 233*c217d954SCole Faust 234*c217d954SCole Faust class FixtureName : public framework::Fixture 235*c217d954SCole Faust { 236*c217d954SCole Faust public: 237*c217d954SCole Faust template <typename T> 238*c217d954SCole Faust void setup(T num) 239*c217d954SCole Faust { 240*c217d954SCole Faust _num = num; 241*c217d954SCole Faust } 242*c217d954SCole Faust 243*c217d954SCole Faust protected: 244*c217d954SCole Faust int _num; 245*c217d954SCole Faust }; 246*c217d954SCole Faust 247*c217d954SCole Faust FIXTURE_DATA_TEST_CASE(TestCaseName, FixtureName, DatasetMode::PRECOMMIT, framework::make("Numbers", {1, 2, 3})) 248*c217d954SCole Faust { 249*c217d954SCole Faust ARM_COMPUTE_ASSERT(_num < 4); 250*c217d954SCole Faust } 251*c217d954SCole Faust 252*c217d954SCole Faust@subsubsection tests_overview_test_cases_register_fixture_data_test_case Registering a fixture as data test case 253*c217d954SCole Faust 254*c217d954SCole FaustAllows to use a fixture directly as parameterized test case. Instead of 255*c217d954SCole Faustdefining a new test function the run method of the fixture will be executed. 256*c217d954SCole FaustThe setup method of the fixture needs to be a template and has to accept inputs 257*c217d954SCole Faustfrom the dataset as arguments. The dataset will be used to generate versions of 258*c217d954SCole Faustthe test case with different inputs. 259*c217d954SCole Faust 260*c217d954SCole Faust- First argument is the name of the test case (has to be unique within the 261*c217d954SCole Faust enclosing test suite). 262*c217d954SCole Faust- Second argument is the class name of the fixture. 263*c217d954SCole Faust- Third argument is the dataset mode in which the test will be active. 264*c217d954SCole Faust- Fourth argument is the dataset. 265*c217d954SCole Faust 266*c217d954SCole Faust 267*c217d954SCole Faust class FixtureName : public framework::Fixture 268*c217d954SCole Faust { 269*c217d954SCole Faust public: 270*c217d954SCole Faust template <typename T> 271*c217d954SCole Faust void setup(T num) 272*c217d954SCole Faust { 273*c217d954SCole Faust _num = num; 274*c217d954SCole Faust } 275*c217d954SCole Faust 276*c217d954SCole Faust void run() override 277*c217d954SCole Faust { 278*c217d954SCole Faust ARM_COMPUTE_ASSERT(_num < 4); 279*c217d954SCole Faust } 280*c217d954SCole Faust 281*c217d954SCole Faust protected: 282*c217d954SCole Faust int _num; 283*c217d954SCole Faust }; 284*c217d954SCole Faust 285*c217d954SCole Faust REGISTER_FIXTURE_DATA_TEST_CASE(TestCaseName, FixtureName, DatasetMode::PRECOMMIT, framework::make("Numbers", {1, 2, 3})); 286*c217d954SCole Faust 287*c217d954SCole Faust@section writing_tests Writing validation tests 288*c217d954SCole Faust 289*c217d954SCole FaustBefore starting a new test case have a look at the existing ones. They should 290*c217d954SCole Faustprovide a good overview how test cases are structured. 291*c217d954SCole Faust 292*c217d954SCole Faust- The C++ reference needs to be added to `tests/validation/CPP/`. The 293*c217d954SCole Faust reference function is typically a template parameterized by the underlying 294*c217d954SCole Faust value type of the `SimpleTensor`. This makes it easy to specialise for 295*c217d954SCole Faust different data types. 296*c217d954SCole Faust- If all backends have a common interface it makes sense to share the setup 297*c217d954SCole Faust code. This can be done by adding a fixture in 298*c217d954SCole Faust `tests/validation/fixtures/`. Inside of the `setup` method of a fixture 299*c217d954SCole Faust the tensors can be created and initialised and the function can be configured 300*c217d954SCole Faust and run. The actual test will only have to validate the results. To be shared 301*c217d954SCole Faust among multiple backends the fixture class is usually a template that accepts 302*c217d954SCole Faust the specific types (data, tensor class, function class etc.) as parameters. 303*c217d954SCole Faust- The actual test cases need to be added for each backend individually. 304*c217d954SCole Faust Typically the will be multiple tests for different data types and for 305*c217d954SCole Faust different execution modes, e.g. precommit and nightly. 306*c217d954SCole Faust 307*c217d954SCole Faust@section tests_running_tests Running tests 308*c217d954SCole Faust@subsection tests_running_tests_benchmark_and_validation Benchmarking and validation suites 309*c217d954SCole Faust@subsubsection tests_running_tests_benchmarking_filter Filter tests 310*c217d954SCole FaustAll tests can be run by invoking 311*c217d954SCole Faust 312*c217d954SCole Faust ./arm_compute_benchmark ./data 313*c217d954SCole Faust 314*c217d954SCole Faustwhere `./data` contains the assets needed by the tests. 315*c217d954SCole Faust 316*c217d954SCole FaustIf only a subset of the tests has to be executed the `--filter` option takes a 317*c217d954SCole Faustregular expression to select matching tests. 318*c217d954SCole Faust 319*c217d954SCole Faust ./arm_compute_benchmark --filter='^NEON/.*AlexNet' ./data 320*c217d954SCole Faust 321*c217d954SCole Faust@note Filtering will be much faster if the regular expression starts from the start ("^") or end ("$") of the line. 322*c217d954SCole Faust 323*c217d954SCole FaustAdditionally each test has a test id which can be used as a filter, too. 324*c217d954SCole FaustHowever, the test id is not guaranteed to be stable when new tests are added. 325*c217d954SCole FaustOnly for a specific build the same the test will keep its id. 326*c217d954SCole Faust 327*c217d954SCole Faust ./arm_compute_benchmark --filter-id=10 ./data 328*c217d954SCole Faust 329*c217d954SCole FaustAll available tests can be displayed with the `--list-tests` switch. 330*c217d954SCole Faust 331*c217d954SCole Faust ./arm_compute_benchmark --list-tests 332*c217d954SCole Faust 333*c217d954SCole FaustMore options can be found in the `--help` message. 334*c217d954SCole Faust 335*c217d954SCole Faust@subsubsection tests_running_tests_benchmarking_runtime Runtime 336*c217d954SCole FaustBy default every test is run once on a single thread. The number of iterations 337*c217d954SCole Faustcan be controlled via the `--iterations` option and the number of threads via 338*c217d954SCole Faust`--threads`. 339*c217d954SCole Faust 340*c217d954SCole Faust@subsubsection tests_running_tests_benchmarking_output Output 341*c217d954SCole FaustBy default the benchmarking results are printed in a human readable format on 342*c217d954SCole Faustthe command line. The colored output can be disabled via `--no-color-output`. 343*c217d954SCole FaustAs an alternative output format JSON is supported and can be selected via 344*c217d954SCole Faust`--log-format=json`. To write the output to a file instead of stdout the 345*c217d954SCole Faust`--log-file` option can be used. 346*c217d954SCole Faust 347*c217d954SCole Faust@subsubsection tests_running_tests_benchmarking_mode Mode 348*c217d954SCole FaustTests contain different datasets of different sizes, some of which will take several hours to run. 349*c217d954SCole FaustYou can select which datasets to use by using the `--mode` option, we recommed you use `--mode=precommit` to start with. 350*c217d954SCole Faust 351*c217d954SCole Faust@subsubsection tests_running_tests_benchmarking_instruments Instruments 352*c217d954SCole FaustYou can use the `--instruments` option to select one or more instruments to measure the execution time of the benchmark tests. 353*c217d954SCole Faust 354*c217d954SCole Faust`PMU` will try to read the CPU PMU events from the kernel (They need to be enabled on your platform) 355*c217d954SCole Faust 356*c217d954SCole Faust`MALI` will try to collect Arm® Mali™ hardware performance counters. (You need to have a recent enough Arm® Mali™ driver) 357*c217d954SCole Faust 358*c217d954SCole Faust`WALL_CLOCK_TIMER` will measure time using `gettimeofday`: this should work on all platforms. 359*c217d954SCole Faust 360*c217d954SCole FaustYou can pass a combinations of these instruments: `--instruments=PMU,MALI,WALL_CLOCK_TIMER` 361*c217d954SCole Faust 362*c217d954SCole Faust@note You need to make sure the instruments have been selected at compile time using the `pmu=1` or `mali=1` scons options. 363*c217d954SCole Faust 364*c217d954SCole Faust@subsubsection tests_running_examples Examples 365*c217d954SCole Faust 366*c217d954SCole FaustTo run all the precommit validation tests: 367*c217d954SCole Faust 368*c217d954SCole Faust LD_LIBRARY_PATH=. ./arm_compute_validation --mode=precommit 369*c217d954SCole Faust 370*c217d954SCole FaustTo run the OpenCL precommit validation tests: 371*c217d954SCole Faust 372*c217d954SCole Faust LD_LIBRARY_PATH=. ./arm_compute_validation --mode=precommit --filter="^CL.*" 373*c217d954SCole Faust 374*c217d954SCole FaustTo run the Arm® Neon™ precommit benchmark tests with PMU and Wall Clock timer in miliseconds instruments enabled: 375*c217d954SCole Faust 376*c217d954SCole Faust LD_LIBRARY_PATH=. ./arm_compute_benchmark --mode=precommit --filter="^NEON.*" --instruments="pmu,wall_clock_timer_ms" --iterations=10 377*c217d954SCole Faust 378*c217d954SCole FaustTo run the OpenCL precommit benchmark tests with OpenCL kernel timers in miliseconds enabled: 379*c217d954SCole Faust 380*c217d954SCole Faust LD_LIBRARY_PATH=. ./arm_compute_benchmark --mode=precommit --filter="^CL.*" --instruments="opencl_timer_ms" --iterations=10 381*c217d954SCole Faust 382*c217d954SCole Faust@note You might need to export the path to OpenCL library as well in your LD_LIBRARY_PATH if Compute Library was built with OpenCL enabled. 383*c217d954SCole Faust*/ 384*c217d954SCole Faust} // namespace test 385*c217d954SCole Faust} // namespace arm_compute 386