| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- /* ----------------------------------------------------------------------
- * Project: CMSIS DSP Library
- * Title: IORunner.cpp
- * Description: IORunner
- *
- * Runner implementation for runner running on device
- * under test
- *
- * $Date: 20. June 2019
- * $Revision: V1.0.0
- *
- * Target Processor: Cortex-M cores
- * -------------------------------------------------------------------- */
- /*
- * Copyright (C) 2010-2019 ARM Limited or its affiliates. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "Test.h"
- #include <string>
- #include <cstddef>
- #include <cstdlib>
- #include <cstdio>
- #include "IORunner.h"
- #include "Error.h"
- #include "Timing.h"
- #include "arm_math_types.h"
- #include "Calibrate.h"
- #ifdef CORTEXA
- #define CALIBNB 1
- #else
- #define CALIBNB 20
- #endif
- using namespace std;
- namespace Client
- {
-
- IORunner::IORunner(IO *io,PatternMgr *mgr, Testing::RunningMode runningMode):m_io(io), m_mgr(mgr)
- {
- volatile Testing::cycles_t current;
- this->m_runningMode = runningMode;
- // Set running mode on PatternMgr.
- if (runningMode == Testing::kDumpOnly)
- {
- mgr->setDumpMode();
- }
- if (runningMode == Testing::kTestAndDump)
- {
- mgr->setTestAndDumpMode();
- }
- initCycleMeasurement();
- /*
- For calibration :
- Calibration means, in this context, removing the overhad of calling
- a C++ function pointer from the cycle measurements.
- */
- Calibrate c((Testing::testID_t)0);
- Client::Suite *s=(Client::Suite *)&c;
- Client::test t = (Client::test)&Calibrate::empty;
- calibration = 0;
-
- /*
- For calibration, we measure the time it takes to call 20 times an empty benchmark and compute
- the average.
- (20 is an arbitrary value.)
- This overhead is removed from benchmarks in the Runner..
- Calibration is removed from the python script when external trace is used for the cycles.
- Indeed, in that case the calibration value can only be measured by parsing the trace.
- Otherwise, the calibration is measured below.
- */
- /*
- We want to ensure that the calibration of the overhead of the
- measurement is the same here and when we do the measurement later.
- So to ensure the conditions are always the same, the instruction cache
- and branch predictor are flushed.
- */
- #ifdef CORTEXA
- __set_BPIALL(0);
- __DSB();
- __ISB();
- __set_ICIALLU(0);
- __DSB();
- __ISB();
- #endif
- /*
- We always call the empty function once to ensure it is in the cache
- because it is how the measurement is done.
- */
- if (!m_mgr->HasMemError())
- {
- (s->*t)();
- }
- /*
- We measure the cycles required for a measurement,
- The cycleMeasurement starts, getCycles and cycleMeasurementStop
- should not be in the cache.
- So, for the overhead we always have the value corresponding to
- the code not in cache.
- While for the code itself we have the value for the code in cache.
- */
- /*
- EXTBENCH is set when benchmarking is done through external traces
- instead of using internal counters.
- Currently the post-processing scripts are only supporting traces generated from
- fast models.
- */
- #if defined(EXTBENCH) || defined(CACHEANALYSIS)
- startSection();
- #endif
-
- for(int i=0;i < CALIBNB;i++)
- {
- cycleMeasurementStart();
- if (!m_mgr->HasMemError())
- {
- (s->*t)();
- }
- #ifndef EXTBENCH
- current = getCycles();
- #endif
- calibration += current;
- cycleMeasurementStop();
- }
- #if defined(EXTBENCH) || defined(CACHEANALYSIS)
- stopSection();
- #endif
- #ifndef EXTBENCH
- calibration=calibration / CALIBNB;
- #endif
- }
- // Testing.
- // When false we are in dump mode and the failed assertion are ignored
- // (But exception is taken so assert should be at end of the test and not in the
- // middle )
- IORunner::IORunner(IO *io,PatternMgr *mgr):m_io(io), m_mgr(mgr)
- {
- this->m_runningMode = Testing::kTestOnly;
- }
- IORunner::~IORunner()
- {
-
- }
-
- /** Read driver data to control execution of a suite
- */
- Testing::TestStatus IORunner::run(Suite *s)
- {
- Testing::TestStatus finalResult = Testing::kTestPassed;
- int nbTests = s->getNbTests();
- int failedTests=0;
- Testing::errorID_t error=0;
- unsigned long line = 0;
- char details[200];
- volatile Testing::cycles_t cycles=0;
- Testing::nbParameters_t nbParams;
- // Read node identification (suite)
- m_io->ReadIdentification();
- // Read suite nb of parameters
- nbParams = m_io->ReadNbParameters();
- // Read list of patterns
- m_io->ReadPatternList();
- // Read list of output
- m_io->ReadOutputList();
- // Read list of parameters
- m_io->ReadParameterList(nbParams);
- // Iterate on tests
- for(int i=1; i <= nbTests; i++)
- {
- test t = s->getTest(i);
- Testing::TestStatus result = Testing::kTestPassed;
- error = UNKNOWN_ERROR;
- line = 0;
- cycles = 0;
- details[0]='\0';
- Testing::param_t *paramData=NULL;
- Testing::nbParameterEntries_t entries=0;
- std::vector<Testing::param_t> params(nbParams);
- bool canExecute=true;
- unsigned long dataIndex=0;
- Testing::ParameterKind paramKind;
- // Read test identification (test ID)
- m_io->ReadTestIdentification();
-
-
- if (m_io->hasParam())
- {
- Testing::PatternID_t paramID=m_io->getParamID();
- paramData = m_io->ImportParams(paramID,entries,paramKind);
- dataIndex = 0;
- }
- while(canExecute)
- {
- canExecute = false;
-
- if (m_io->hasParam() && paramData)
- {
- // Load new params
- for(unsigned long j=0; j < nbParams ; j++)
- {
- params[j] = paramData[nbParams*dataIndex+j];
- }
- // Update condition for new execution
- dataIndex += 1;
- canExecute = dataIndex < entries;
- }
- // Execute test
- try {
- // Prepare memory for test
- // setUp will generally load patterns
- // and do specific initialization for the tests
- s->setUp(m_io->CurrentTestID(),params,m_mgr);
-
- // Run the test once to force the code to be in cache.
- // By default it is disabled in the suite.
- #ifdef CORTEXA
- __set_BPIALL(0);
- __DSB();
- __ISB();
- __set_ICIALLU(0);
- __DSB();
- __ISB();
- #endif
- /* If cache analysis mode, we don't force the code to be in cache. */
- #if !defined(CACHEANALYSIS)
- if (s->isForcedInCache())
- {
- if (!m_mgr->HasMemError())
- {
- (s->*t)();
- }
- }
- #endif
- // Run the test
- cycleMeasurementStart();
- #if defined(EXTBENCH) || defined(CACHEANALYSIS)
- startSection();
- #endif
- if (!m_mgr->HasMemError())
- {
- (s->*t)();
- }
- #if defined(EXTBENCH) || defined(CACHEANALYSIS)
- stopSection();
- #endif
- #ifndef EXTBENCH
- cycles=getCycles();
- cycles=cycles-calibration;
- #endif
- cycleMeasurementStop();
- }
- catch(Error &ex)
- {
- cycleMeasurementStop();
- // In dump only mode we ignore the tests
- // since the reference patterns are not loaded
- // so tests will fail.
- if (this->m_runningMode != Testing::kDumpOnly)
- {
- error = ex.errorID;
- line = ex.lineNumber;
- strcpy(details,ex.details);
- result=Testing::kTestFailed;
- }
- }
- catch (...) {
- cycleMeasurementStop();
- // In dump only mode we ignore the tests
- // since the reference patterns are not loaded
- // so tests will fail.
- if (this->m_runningMode != Testing::kDumpOnly)
- {
- result = Testing::kTestFailed;
- error = UNKNOWN_ERROR;
- line = 0;
- }
- }
- try {
- // Clean memory after this test
- // May dump output and do specific cleaning for a test
- s->tearDown(m_io->CurrentTestID(),m_mgr);
- }
- catch(...)
- {
-
- }
- if (m_mgr->HasMemError())
- {
- /* We keep the current error if set.
- */
- if (result == Testing::kTestPassed)
- {
- result = Testing::kTestFailed;
- error = MEMORY_ALLOCATION_ERROR;
- line = 0;
- }
- }
-
- // Free all memory of memory manager so that next test
- // is starting in a clean and controlled tests
- m_mgr->freeAll();
-
- // Dump test status to output
- m_io->DispStatus(result,error,line,cycles);
- m_io->DispErrorDetails(details);
- m_io->DumpParams(params);
- }
- if (paramData)
- {
- if (paramKind == Testing::kDynamicBuffer)
- {
- free(paramData);
- }
- paramData = NULL;
- }
- if (result == Testing::kTestFailed)
- {
- failedTests ++;
- finalResult = Testing::kTestFailed;
- }
- }
- // Signal end of group processing to output
- m_io->EndGroup();
- return(finalResult);
- }
- /** Read driver data to control execution of a group
- */
- Testing::TestStatus IORunner::run(Group *g)
- {
- int nbTests = g->getNbContainer();
- int failedTests=0;
- // Read Node identification
- m_io->ReadIdentification();
-
- Testing::TestStatus finalResult = Testing::kTestPassed;
- // Iterate on group elements
- for(int i=1; i <= nbTests; i++)
- {
- TestContainer *c = g->getContainer(i);
- if (c != NULL)
- {
- // Execute runner for this group
- Testing::TestStatus result = c->accept(this);
- if (result == Testing::kTestFailed)
- {
- failedTests ++;
- finalResult = Testing::kTestFailed;
- }
- }
-
- }
- // Signal to output that processing of this group has finished.
- m_io->EndGroup();
- return(finalResult);
- }
- }
|