/** * @file tst_sm_time.c * @author NXP Semiconductors * @version 1.0 * @par LICENSE * * Copyright 2016,2020 NXP * SPDX-License-Identifier: Apache-2.0 * * @par Description * (APDU) Execution time measurement utility library * @par HISTORY * 1.0 03-apr-2015 : Initial version * *****************************************************************************/ /******************************************************************* * standard include files *******************************************************************/ #include #include #include #include #include /******************************************************************* * project specific include files *******************************************************************/ #include "tst_sm_util.h" #include "tst_sm_time.h" /******************************************************************* * global variables and struct definitions *******************************************************************/ /* * API */ #ifdef SM_TIME_USE_TIMEVAL #define CLOCK_MONOTONIC 0 int clock_gettime(int X, struct timeval *tv) { #ifdef MSC_VER ULONGLONG msSinceBoot = GetTickCount64(); #else ULONGLONG msSinceBoot = GetTickCount(); #endif tv->tv_sec = (long) (msSinceBoot / 1000); tv->tv_usec = (msSinceBoot % 1000) * 1000; return (0); } #endif // SM_TIME_USE_TIMEVAL /** * Initiate measurement of execution time * * @param[in,out] mPair In: Pointer to an allocated axTimeMeasurement_t structure */ void initMeasurement(axTimeMeasurement_t *mPair) { mPair->tStart.tv_sec = 0; #ifdef SM_TIME_USE_TIMEVAL mPair->tStart.tv_usec = 0; #endif #ifdef SM_TIME_USE_TIMESPEC mPair->tStart.tv_nsec = 0; #endif mPair->tEnd.tv_sec = 0; #ifdef SM_TIME_USE_TIMEVAL mPair->tEnd.tv_usec = 0; #endif #ifdef SM_TIME_USE_TIMESPEC mPair->tEnd.tv_nsec = 0; #endif clock_gettime(CLOCK_MONOTONIC, &(mPair->tStart)); } /** * Conclude measurement of execution time. Matches a call to ::initMeasurement * * @param[in,out] mPair In: Pointer to an allocated axTimeMeasurement_t structure */ void concludeMeasurement(axTimeMeasurement_t *mPair) { clock_gettime(CLOCK_MONOTONIC, &(mPair->tEnd)); } /** * Calculates (and returns) execution time in ms (milli seconds). * \pre Call to ::initMeasurement * \pre Call to ::concludeMeasurement * * @param[in,out] mPair In: Pointer to an allocated axTimeMeasurement_t structure * @returns Execution time in ms (milli seconds) */ long getMeasurement(axTimeMeasurement_t *mPair) { long startMillis; long endMillis; long deltaMillis; // printf("Start: Sec: 0x%08x - nSec: 0x%08x\n", mPair->tStart.tv_sec, mPair->tStart.tv_nsec); // printf("End : Sec: 0x%08x - nSec: 0x%08x\n", mPair->tEnd.tv_sec, mPair->tEnd.tv_nsec); #ifdef SM_TIME_USE_TIMEVAL startMillis = (mPair->tStart.tv_sec * 1000) + (mPair->tStart.tv_usec / 1000); endMillis = (mPair->tEnd.tv_sec * 1000) + (mPair->tEnd.tv_usec / 1000); #endif #ifdef SM_TIME_USE_TIMESPEC startMillis = (mPair->tStart.tv_sec * 1000) + (mPair->tStart.tv_nsec / 1000000); endMillis = (mPair->tEnd.tv_sec * 1000) + (mPair->tEnd.tv_nsec / 1000000); #endif deltaMillis = endMillis - startMillis; // printf("Delta: %" PRIi32 " ms\n", deltaMillis); return deltaMillis; } /** * Create a report fragment based on measurements contained in \p msArray * * @param[in] fHandle Valid file handle to contain report fragment * @param[in] szMessage Label to use in report fragment * @param[in] msArray Array containing (execution time) measurements (in ms) * @param[in] nMeasurement Amount of measurements contained in \p msArray * @param[in] reportMode Defines style of report (construct bitpattern with e.g. ::AX_MEASURE_REPORT_VERBOSE or ::AX_MEASURE_ECHO_STDOUT) */ void axSummarizeMeasurement(FILE *fHandle, char *szMessage, long *msArray, int nMeasurement, int reportMode) { int i; long averaged = 0; long minValue = 0; long maxValue = 0; int fEchoStdout = 0; int fReportVerbose = 0; FILE *fHandleArray[2]; int nHandle = 2; int nOut; fEchoStdout = ((reportMode & AX_MEASURE_ECHO_MASK) == AX_MEASURE_ECHO_STDOUT); fReportVerbose = ((reportMode & AX_MEASURE_REPORT_MASK) == AX_MEASURE_REPORT_VERBOSE); if (fEchoStdout) { fHandleArray[0] = fHandle; fHandleArray[1] = stdout; nHandle = 2; } else { fHandleArray[0] = fHandle; nHandle = 1; } if (nMeasurement > 0) { minValue = msArray[0]; maxValue = msArray[0]; } else { for (nOut=0; nOut maxValue) ? msArray[i] : maxValue; } averaged /= nMeasurement; for (nOut=0; nOut higherBound)) { printf("*** Execution speed slower than specified: %" PRIu32 " > %" PRIu32 "\n", (uint32_t)measured, (uint32_t)higherBound); status = (severity == AX_TIME_EVAL_FATAL ? 0 : 1); } break; default: printf("Severity level not defined.\n"); status = 0; } return status; } #endif //!defined(TGT_A71CH) && !defined(TGT_A71CL)