blob: 0b531f6e8022a956fcf8769ba7eb08e1af559c1b [file] [log] [blame]
/**
* @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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
/*******************************************************************
* 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<nHandle; nOut++)
{
fprintf(fHandleArray[nOut], "%s: No valid amount of measurements ( %" PRIi32 ")\n", szMessage, (int32_t)nMeasurement);
}
return;
}
for (i=0; i<nMeasurement; i++)
{
if (fReportVerbose)
{
for (nOut=0; nOut<nHandle; nOut++)
{
fprintf(fHandleArray[nOut], "%s: %" PRIu32 " ms\n", szMessage, (uint32_t)msArray[i]);
}
}
averaged += msArray[i];
minValue = (msArray[i] < minValue) ? msArray[i] : minValue;
maxValue = (msArray[i] > maxValue) ? msArray[i] : maxValue;
}
averaged /= nMeasurement;
for (nOut=0; nOut<nHandle; nOut++)
{
fprintf(fHandleArray[nOut], "Exec Time: %s:\n\tAverage ( %" PRIu32 " measurements): %" PRIu32 " ms\n",
szMessage, (uint32_t)nMeasurement, (uint32_t)averaged);
fprintf(fHandleArray[nOut], "\tMinimum: %" PRIu32 " ms\n", (uint32_t)minValue);
fprintf(fHandleArray[nOut], "\tMaximum: %" PRIu32 " ms\n", (uint32_t)maxValue);
}
}
#if !defined(TGT_A71CH) && !defined(TGT_A71CL)
/**
* @param szMessage
* @param measured
* @param lowerBound measured must be higher than lowerBound in case lowerBound is different from 0
* @param higherBound measured must be lower than higherBound in case higherBound is different from 0
* @param severity
* @return
*/
int evalMeasurement(char *szMessage, long measured, long lowerBound, long higherBound, axExecTimeEval_t severity) {
int status = 1;
printf("%s: %" PRIu32 " ms\n", szMessage, (uint32_t)measured);
switch (severity) {
case AX_TIME_EVAL_IGNORE:
break;
case AX_TIME_EVAL_WARNING:
case AX_TIME_EVAL_FATAL:
if ( (lowerBound != 0) && (measured < lowerBound) ) {
printf("*** Execution speed faster than specified: %" PRIu32 " < %" PRIu32 "\n", (uint32_t)measured, (uint32_t)lowerBound);
status = (severity == AX_TIME_EVAL_FATAL ? 0 : 1);
}
if ( (higherBound != 0) && (measured > 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)