1 /* ---------------------------------------------------------------------- 2 * Project: CMSIS DSP Library 3 * Title: Test.h 4 * Description: Test Framework Header 5 * 6 * $Date: 20. June 2019 7 * $Revision: V1.0.0 8 * 9 * Target Processor: Cortex-M cores 10 * -------------------------------------------------------------------- */ 11 /* 12 * Copyright (C) 2010-2019 ARM Limited or its affiliates. All rights reserved. 13 * 14 * SPDX-License-Identifier: Apache-2.0 15 * 16 * Licensed under the Apache License, Version 2.0 (the License); you may 17 * not use this file except in compliance with the License. 18 * You may obtain a copy of the License at 19 * 20 * www.apache.org/licenses/LICENSE-2.0 21 * 22 * Unless required by applicable law or agreed to in writing, software 23 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 24 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 * See the License for the specific language governing permissions and 26 * limitations under the License. 27 */ 28 #ifndef _TEST_H_ 29 #define _TEST_H_ 30 31 #include <cstdlib> 32 #include <vector> 33 #include <cstdio> 34 #include "arm_math_types.h" 35 #include "arm_math_types_f16.h" 36 37 38 // This special value means no limit on the number of samples. 39 // It is used when importing patterns and we want to read 40 // all the samples contained in the pattern. 41 #define MAX_NB_SAMPLES 0 42 43 // Pattern files are containing hexadecimal values. 44 // So we need to be able to convert some int into float without convertion 45 #define TOINT16(v) *((uint16_t*)&v) 46 #define TOINT32(v) *((uint32_t*)&v) 47 #define TOINT64(v) *((uint64_t*)&v) 48 // Or convert some float into a uint32 or uint64 without convertion 49 #define TOTYP(TYP,v) *((TYP*)&v) 50 // So it is a cast and not a data conversion. 51 // (uint32_t)1.0 would give 1. We want the hexadecimal representation of the float. 52 // TOINT32(1.0) can be used 53 54 55 namespace Testing 56 { 57 enum TestStatus 58 { 59 kTestFailed=0, 60 kTestPassed=1 61 }; 62 63 /* In Dump only, reference patterns are never read. 64 So tests are failing 65 and we dump output. 66 In this mode we are only interested in the output data and 67 not the test status. 68 69 In test only mode, no output is dumped. 70 */ 71 enum RunningMode 72 { 73 kTestOnly=0, 74 kDumpOnly=1, 75 kTestAndDump=2 76 }; 77 78 79 80 81 // test ID are ID of nodes in the tree of tests. 82 // So a group ID, suite ID or test ID all have the same type 83 // testID_t 84 typedef unsigned long testID_t; 85 typedef unsigned long outputID_t; 86 typedef unsigned long PatternID_t; 87 88 typedef unsigned long testIndex_t; 89 typedef unsigned long nbSamples_t; 90 typedef unsigned long errorID_t; 91 92 93 94 typedef uint32_t cycles_t; 95 typedef unsigned long nbMeasurements_t; 96 97 // parameter value 98 // (always int since we need to be able to iterate on 99 // different parameter values which are often dimensions of 100 // input data) 101 typedef int param_t; 102 // Number of parameters for a given configuration 103 typedef unsigned long nbParameters_t; 104 // Number of parameter configurations 105 typedef unsigned long nbParameterEntries_t; 106 107 // To know if parameter array is malloc buffer or static buffer in C array 108 enum ParameterKind 109 { 110 kStaticBuffer=0, 111 kDynamicBuffer=1, 112 }; 113 114 } 115 116 namespace Client 117 { 118 119 120 121 /* 122 123 Client code 124 125 */ 126 127 128 129 class Suite; 130 class Group; 131 132 133 // Type of a test function 134 // It is not a function pointer (because the function is 135 // a method of a CPP class) 136 typedef void (Suite::*test)(); 137 138 /* 139 140 API of Memory managers used in the test framework 141 142 */ 143 class Memory 144 { 145 public: 146 // Allocate a new buffer of size length 147 // and generate a pointer to this buffer. 148 // It does not imply that any malloc is done. 149 // It depends on how the Memory manager is implemented. 150 virtual char *NewBuffer(size_t length)=0; 151 152 // Free all the memory allocated by the memory manager 153 // and increment the memory generation number. 154 virtual void FreeMemory()=0; 155 156 // Memory allocation errors must be tracked during a test. 157 // The runner should force the test status to FAILED 158 // when a memory error occured. 159 virtual bool HasMemError()=0; 160 161 // When memory manager is supporting tail 162 // then we can check that the tail of the buffer has not been 163 // corrupted. 164 // The tail being the additional words after the end of the buffer allocated 165 // by the memory manager so that there is some seperation between 166 // successive buffers. 167 // When memory manager is not supporting tail, this function should 168 // always succeed. 169 virtual bool IsTailEmpty(char *, size_t)=0; 170 171 172 // Get the memory generation number generation()173 unsigned long generation() 174 { 175 return(m_generation); 176 } 177 178 protected: 179 unsigned long m_generation=0; 180 }; 181 182 183 // A runner is a class driving the tests 184 // It can use information from driving files 185 // or in the future could communicate with a process 186 // on a host computer which would be the real driver of the 187 // testing. 188 // It is following the visitor pattern. IT is the reason for an accept 189 // function in Group class. 190 // Run is the visitor 191 class Runner 192 { 193 public: 194 virtual Testing::TestStatus run(Suite*) = 0; 195 virtual Testing::TestStatus run(Group*) = 0; 196 }; 197 198 // Abstract the IO needs of the test framework. 199 // IO could be done from semihosting, socket, C array in memory etc ... 200 class IO 201 { 202 public: 203 204 /** Read the identification of a node from driver data. 205 206 Update the node kind and node id and local folder. 207 To be used for group and suite. Generally update 208 the path to the folder by using this new local folder 209 which is appended to the path. 210 */ 211 virtual void ReadIdentification()=0; 212 213 /** Read the identification of a node driver data. 214 215 Update the node kind and node id and local folder. 216 */ 217 virtual void ReadTestIdentification()=0; 218 219 /** Read the number of parameters for all the tests in a suite 220 221 Used for benchmarking. Same functions executed with 222 different initializations controlled by the parameters. 223 224 */ 225 virtual Testing::nbParameters_t ReadNbParameters()=0; 226 227 /** Dump the test status 228 229 For format of output, refer to Python script. 230 The format must be coherent with the Python script 231 parsing the output. 232 */ 233 virtual void DispStatus(Testing::TestStatus,Testing::errorID_t,unsigned long,Testing::cycles_t cycles)=0; 234 235 236 /** Dump additional details for the error 237 238 For instance, for SNR error, it may contain the SNR value. 239 */ 240 virtual void DispErrorDetails(const char* )=0; 241 242 /** Dump parameters for a test 243 244 When a test is run several time with different 245 parameters for benchmarking, 246 the parameters are displayed after test status. 247 Line should begin with b 248 */ 249 virtual void DumpParams(std::vector<Testing::param_t>&)=0; 250 251 252 /** Dump an end of group/suite to output 253 254 Used by Python script parsing the output. 255 256 */ 257 virtual void EndGroup()=0; 258 259 /** Get the zize of a pattern in this suite. 260 261 Pattern is identified with an ID. 262 Using the local path and ID, the IO implementatiom should 263 be able to access the pattern. 264 265 The path do not have to be a file path. Just a way 266 to identify patterns in a suite and know 267 how to access them. 268 269 */ 270 virtual Testing::nbSamples_t GetPatternSize(Testing::PatternID_t)=0; 271 272 /** Get the size of a parameter pattern in this suite. 273 274 Parameter is identified with an ID. 275 Using the local path and ID, the IO implementatiom should 276 be able to access the data. 277 278 The path do not have to be a file path. Just a way 279 to identify data in a suite and know 280 how to access them. 281 282 */ 283 //virtual Testing::nbSamples_t GetParameterSize(Testing::PatternID_t id)=0; 284 285 /** Check if some parameters are controlling this test 286 */ 287 virtual bool hasParam()=0; 288 289 /** Get ID of parameter generator 290 */ 291 virtual Testing::PatternID_t getParamID()=0; 292 293 /** Import pattern. 294 295 The nb field can be used to limit the number of samples read 296 to a smaller value than the number of samples available in the 297 pattern. 298 299 */ 300 virtual void ImportPattern_f64(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 301 virtual void ImportPattern_f32(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 302 #if !defined( __CC_ARM ) && defined(ARM_FLOAT16_SUPPORTED) 303 virtual void ImportPattern_f16(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 304 #endif 305 virtual void ImportPattern_q63(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 306 virtual void ImportPattern_q31(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 307 virtual void ImportPattern_q15(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 308 virtual void ImportPattern_q7(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 309 virtual void ImportPattern_u64(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 310 virtual void ImportPattern_u32(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 311 virtual void ImportPattern_u16(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 312 virtual void ImportPattern_u8(Testing::PatternID_t,char*,Testing::nbSamples_t nb=MAX_NB_SAMPLES)=0; 313 314 /** Import params. 315 316 This is allocating memory. 317 The runner should free it after use. 318 319 It is not using the Memory manager since tests don't have access 320 to the array of parameters. 321 322 They receive parameters as a vector argument for the setUp fucntion. 323 */ 324 virtual Testing::param_t* ImportParams(Testing::PatternID_t,Testing::nbParameterEntries_t &,Testing::ParameterKind &)=0; 325 326 /** Dump pattern. 327 328 The output ID (and test ID) must be used to uniquely identify 329 the dump. 330 331 332 */ 333 virtual void DumpPattern_f64(Testing::outputID_t,Testing::nbSamples_t nb, float64_t*)=0; 334 virtual void DumpPattern_f32(Testing::outputID_t,Testing::nbSamples_t nb, float32_t*)=0; 335 #if !defined( __CC_ARM ) && defined(ARM_FLOAT16_SUPPORTED) 336 virtual void DumpPattern_f16(Testing::outputID_t,Testing::nbSamples_t nb, float16_t*)=0; 337 #endif 338 virtual void DumpPattern_q63(Testing::outputID_t,Testing::nbSamples_t nb, q63_t*)=0; 339 virtual void DumpPattern_q31(Testing::outputID_t,Testing::nbSamples_t nb, q31_t*)=0; 340 virtual void DumpPattern_q15(Testing::outputID_t,Testing::nbSamples_t nb, q15_t*)=0; 341 virtual void DumpPattern_q7(Testing::outputID_t,Testing::nbSamples_t nb, q7_t*)=0; 342 virtual void DumpPattern_u64(Testing::outputID_t,Testing::nbSamples_t nb, uint64_t*)=0; 343 virtual void DumpPattern_u32(Testing::outputID_t,Testing::nbSamples_t nb, uint32_t*)=0; 344 virtual void DumpPattern_u16(Testing::outputID_t,Testing::nbSamples_t nb, uint16_t*)=0; 345 virtual void DumpPattern_u8(Testing::outputID_t,Testing::nbSamples_t nb, uint8_t*)=0; 346 347 /** Import list of patterns from the driver 348 for current suite. 349 350 This list is used to identify a pattern from its pattern ID. 351 The information of this list (local to the suite) is 352 combined with the path to identify patterns in other part of the class. 353 354 */ 355 virtual void ReadPatternList()=0; 356 357 /** Import list of output from the driver 358 for current suite. 359 360 This list is used to identify an output from its pattern ID (and current test ID) 361 The information of this list (local to the suite) is 362 combined with the path and current test ID 363 to identify output in other part of the class. 364 365 */ 366 virtual void ReadOutputList()=0; 367 368 /** Import list of parameters from the driver 369 for current suite. 370 371 This list is used to control a functions with different parameters 372 for benchmarking purpose. 373 374 A parameter can be a file of parameters or a generator 375 of parameters (cartesian product of lists only). 376 377 */ 378 virtual void ReadParameterList(Testing::nbParameters_t)=0; 379 380 /** Get current node ID 381 group, suite or test. A group of test is considered as a test hence 382 the name of the function. 383 384 */ 385 virtual Testing::testID_t CurrentTestID()=0; 386 }; 387 388 389 // A pattern manager is making the link between 390 // IO and the Memory manager. 391 // It knows how to import patterns into memory or dump 392 // memory into outputs (output which may be different from a file) 393 // The running mode is controlling if dumping is disabled or not. 394 // But cna also be used by the runner to know if test results must be ignored or not. 395 // Pattern manager is used by the tests 396 // In current version load and dump functions are visible to any body. 397 // In theory they should only be visible to Patterns 398 class PatternMgr 399 { 400 public: 401 PatternMgr(IO*,Memory*); 402 403 /** In those loading APIs, nb samples is coming from the pattern read. 404 maxSamples is coming from the test. 405 406 A test does not know what is the length of a pattern since the test 407 has no visiblity on how the pattern is imported (file, serial port, include files 408 etc ...). 409 410 So the test is specifying the max sampls it needs. 411 The pattern is specifying its lengths. 412 413 Those functions are importing at most what is needed and what is available. 414 415 */ 416 float64_t *load_f64(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 417 float32_t *load_f32(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 418 #if !defined( __CC_ARM ) && defined(ARM_FLOAT16_SUPPORTED) 419 float16_t *load_f16(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 420 #endif 421 q63_t *load_q63(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 422 q31_t *load_q31(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 423 q15_t *load_q15(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 424 q7_t *load_q7(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 425 426 uint64_t *load_u64(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 427 uint32_t *load_u32(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 428 uint16_t *load_u16(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 429 uint8_t *load_u8(Testing::PatternID_t,Testing::nbSamples_t&,Testing::nbSamples_t maxSamples=MAX_NB_SAMPLES); 430 431 /** Create a local pattern. 432 433 Generally it is used as output of a test and has no 434 correspondance to a pattern in the suite. 435 436 */ 437 float64_t *local_f64(Testing::nbSamples_t); 438 float32_t *local_f32(Testing::nbSamples_t); 439 #if !defined( __CC_ARM ) && defined(ARM_FLOAT16_SUPPORTED) 440 float16_t *local_f16(Testing::nbSamples_t); 441 #endif 442 q63_t *local_q63(Testing::nbSamples_t); 443 q31_t *local_q31(Testing::nbSamples_t); 444 q15_t *local_q15(Testing::nbSamples_t); 445 q7_t *local_q7(Testing::nbSamples_t); 446 447 uint64_t *local_u64(Testing::nbSamples_t); 448 uint32_t *local_u32(Testing::nbSamples_t); 449 uint16_t *local_u16(Testing::nbSamples_t); 450 uint8_t *local_u8(Testing::nbSamples_t); 451 452 /** Dump a pattern 453 454 */ 455 void dumpPattern_f64(Testing::outputID_t,Testing::nbSamples_t,float64_t*); 456 void dumpPattern_f32(Testing::outputID_t,Testing::nbSamples_t,float32_t*); 457 #if !defined( __CC_ARM ) && defined(ARM_FLOAT16_SUPPORTED) 458 void dumpPattern_f16(Testing::outputID_t,Testing::nbSamples_t,float16_t*); 459 #endif 460 461 void dumpPattern_q63(Testing::outputID_t,Testing::nbSamples_t,q63_t*); 462 void dumpPattern_q31(Testing::outputID_t,Testing::nbSamples_t,q31_t*); 463 void dumpPattern_q15(Testing::outputID_t,Testing::nbSamples_t,q15_t*); 464 void dumpPattern_q7(Testing::outputID_t,Testing::nbSamples_t,q7_t*); 465 466 void dumpPattern_u64(Testing::outputID_t,Testing::nbSamples_t,uint64_t*); 467 void dumpPattern_u32(Testing::outputID_t,Testing::nbSamples_t,uint32_t*); 468 void dumpPattern_u16(Testing::outputID_t,Testing::nbSamples_t,uint16_t*); 469 void dumpPattern_u8(Testing::outputID_t,Testing::nbSamples_t,uint8_t*); 470 471 /** Free all allocated patterns. 472 473 Just wrapper around the memory manager free function. 474 475 */ 476 void freeAll(); 477 478 /** MeMory manager generation 479 480 */ generation()481 unsigned long generation() 482 { 483 return(m_mem->generation()); 484 } 485 486 // Memory allocation errors must be tracked during a test. 487 // The runner should force the test status to FAILED 488 // when a memory error occured. HasMemError()489 bool HasMemError() 490 { 491 return(m_mem->HasMemError()); 492 } 493 494 // Set by the runner when in dump mode setDumpMode()495 void setDumpMode() 496 { 497 this->m_runningMode = Testing::kDumpOnly; 498 } 499 setTestAndDumpMode()500 void setTestAndDumpMode() 501 { 502 this->m_runningMode = Testing::kTestAndDump; 503 } 504 runningMode()505 Testing::RunningMode runningMode() 506 { 507 return(this->m_runningMode); 508 } 509 IsTailEmpty(char * ptr,size_t length)510 bool IsTailEmpty(char *ptr, size_t length) 511 { 512 return(m_mem->IsTailEmpty(ptr,length)); 513 } 514 515 private: 516 IO *m_io; 517 Memory *m_mem; 518 Testing::RunningMode m_runningMode=Testing::kTestOnly; 519 520 }; 521 522 // TestContainer which is a node of the tree of tests 523 class TestContainer 524 { 525 public: 526 TestContainer(Testing::testID_t); 527 // Used for implementing the visitor pattern. 528 // The visitor pattern is allowing to implement 529 // different Runner for a tree of tests. 530 virtual Testing::TestStatus accept(Runner* v) = 0; 531 protected: 532 // Node ID (test ID) 533 Testing::testID_t m_containerID; 534 }; 535 536 // A suite object 537 // It contains a list of tests 538 // Methods to get a test from the test ID 539 // Initialization and cleanup (setUp and tearDown) to be called 540 // between each test. 541 // Those functions are used by the Runner to execute the tests 542 class Suite:public TestContainer 543 { 544 public: 545 Suite(Testing::testID_t); 546 547 // Prepare memory for a test 548 // (Load input and reference patterns) 549 virtual void setUp(Testing::testID_t,std::vector<Testing::param_t>&,PatternMgr *mgr)=0; 550 551 // Clean memory after a test 552 // Free all memory 553 // DUmp outputs 554 virtual void tearDown(Testing::testID_t,PatternMgr *mgr)=0; 555 556 // Add a test to be run. 557 void addTest(Testing::testID_t,test aTest); 558 559 // Get a test from its index. Used by runner when iterating 560 // on all the tests. Index is not the test ID. 561 // It is the index in internal list of tests 562 test getTest(Testing::testIndex_t); 563 564 // Get number of test in this suite. 565 // The suite is only containing the active tests 566 // (deprecated tests are never generated by python scripts) 567 int getNbTests(); 568 569 // Used for implementing the visitor pattern. 570 // The visitor pattern is allowing to implement 571 // different Runner for a tree of tests. accept(Runner * v)572 virtual Testing::TestStatus accept(Runner* v) override 573 { 574 return(v->run(this)); 575 } 576 577 // Check if, for benchmark, we want to run the code once 578 // before benchmarking it, to force it to be in the I-cache. 579 bool isForcedInCache(); 580 581 // Change the status of the forceInCache mode. 582 void setForceInCache(bool); 583 584 private: 585 bool m_forcedInCache=false; 586 // List of tests 587 std::vector<test> m_tests; 588 // List of tests IDs (since they are not contiguous 589 // due to deprecation feature in python scripts) 590 std::vector<Testing::testID_t> m_testIds; 591 }; 592 593 594 595 // A group 596 // It is possible to add subgroups to a group 597 // and get a subgroup from its ID. 598 class Group:public TestContainer 599 { 600 public: 601 Group(Testing::testID_t); 602 603 // Add a group or suite to this group. 604 void addContainer(TestContainer*); 605 606 // Get a container from its index. (index is not the node ID) 607 TestContainer *getContainer(Testing::testIndex_t); 608 609 // Get number of containers 610 int getNbContainer(); 611 accept(Runner * v)612 virtual Testing::TestStatus accept(Runner* v) override 613 { 614 return(v->run(this)); 615 } 616 617 public: 618 std::vector<TestContainer*> m_groups; 619 620 }; 621 622 623 624 } 625 626 627 #endif 628