Spaces:
Runtime error
Runtime error
/* TA-LIB Copyright (c) 1999-2007, Mario Fortier | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or | |
* without modification, are permitted provided that the following | |
* conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* | |
* - Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in | |
* the documentation and/or other materials provided with the | |
* distribution. | |
* | |
* - Neither name of author nor the names of its contributors | |
* may be used to endorse or promote products derived from this | |
* software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
* REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/* List of contributors: | |
* | |
* Initial Name/description | |
* ------------------------------------------------------------------- | |
* MF Mario Fortier | |
* | |
* | |
* Change history: | |
* | |
* MMDDYY BY Description | |
* ------------------------------------------------------------------- | |
* 112400 MF First version. | |
* | |
*/ | |
/* Description: | |
* Provide utility function internally used in ta_regtest only. | |
*/ | |
/**** Headers ****/ | |
/**** External functions declarations. ****/ | |
/* None */ | |
/**** External variables declarations. ****/ | |
extern int nbProfiledCall; | |
extern double timeInProfiledCall; | |
extern double worstProfiledCall; | |
extern int insufficientClockPrecision; | |
/**** Global variables definitions. ****/ | |
/* Global temporary buffers used while testing. */ | |
TA_Real memoryGuard1 = RESV_PATTERN_MEMGUARD_1; /* Magic number to detect problem. */ | |
TA_Real buf[NB_GLOBAL_BUFFER][TA_NB_OUT_IN][TA_BUF_SIZE]; /* The global buffers. */ | |
TA_Real memoryGuard2 = RESV_PATTERN_MEMGUARD_2; /* Magic number to detect problem. */ | |
TestBuffer gBuffer[5]; /* See initGlobalBuffer. */ | |
/**** Local declarations. ****/ | |
/* None */ | |
/**** Local functions declarations. ****/ | |
static ErrorNumber doRangeTestFixSize( RangeTestFunction testFunction, | |
void *opaqueData, | |
TA_Integer refOutBeg, | |
TA_Integer refOutNbElement, | |
TA_Integer refLookback, | |
const TA_Real *refBuffer, | |
const TA_Integer *refBufferInt, | |
TA_FuncUnstId unstId, | |
TA_Integer fixSize, | |
unsigned int outputNb, | |
unsigned int integerTolerance ); | |
static int dataWithinReasonableRange( TA_Real val1, TA_Real val2, | |
unsigned int outputPosition, | |
TA_FuncUnstId unstId, | |
unsigned int integerTolerance ); | |
static ErrorNumber doRangeTestForOneOutput( RangeTestFunction testFunction, | |
TA_FuncUnstId unstId, | |
void *opaqueData, | |
unsigned int outputNb, | |
unsigned int integerTolerance ); | |
static TA_RetCode CallTestFunction( RangeTestFunction testFunction, | |
TA_Integer startIdx, | |
TA_Integer endIdx, | |
TA_Real *outputBuffer, | |
TA_Integer *outputBufferInt, | |
TA_Integer *outBegIdx, | |
TA_Integer *outNbElement, | |
TA_Integer *lookback, | |
void *opaqueData, | |
unsigned int outputNb, | |
unsigned int *isOutputInteger ); | |
/**** Local variables definitions. ****/ | |
/* None */ | |
/**** Global functions definitions. ****/ | |
static int ta_g_val = 0; | |
static const char *ta_g_wheel = "-\\|/"; | |
void showFeedback() | |
{ | |
if( ta_g_wheel[ta_g_val] == '\0' ) | |
ta_g_val = 0; | |
putchar('\b'); | |
putchar(ta_g_wheel[ta_g_val]); | |
fflush(stdout); | |
ta_g_val++; | |
} | |
void hideFeedback() | |
{ | |
putchar('\b'); | |
fflush(stdout); | |
ta_g_val = 0; | |
} | |
ErrorNumber allocLib() | |
{ | |
TA_RetCode retCode; | |
/* Initialize the library. */ | |
retCode = TA_Initialize(); | |
if( retCode != TA_SUCCESS ) | |
{ | |
printf( "TA_Initialize failed [%d]\n", retCode ); | |
return TA_TESTUTIL_INIT_FAILED; | |
} | |
return TA_TEST_PASS; | |
} | |
ErrorNumber freeLib() | |
{ | |
TA_RetCode retCode; | |
/* For testing purpose */ | |
/* TA_FATAL_RET( "Test again", 100, 200, 0 ); */ | |
retCode = TA_Shutdown(); | |
if( retCode != TA_SUCCESS ) | |
{ | |
printf( "TA_Shutdown failed [%d]\n", retCode ); | |
return TA_TESTUTIL_SHUTDOWN_FAILED; | |
} | |
return TA_TEST_PASS; | |
} | |
void reportError( const char *str, TA_RetCode retCode ) | |
{ | |
TA_RetCodeInfo retCodeInfo; | |
TA_SetRetCodeInfo( retCode, &retCodeInfo ); | |
printf( "%s,%d==%s\n", str, retCode, retCodeInfo.enumStr ); | |
printf( "[%s]\n", retCodeInfo.infoStr ); | |
} | |
/* Need to be called only once. */ | |
void initGlobalBuffer( void ) | |
{ | |
gBuffer[0].in = &buf[0][0][TA_BUF_PREFIX]; | |
gBuffer[0].out0 = &buf[0][1][TA_BUF_PREFIX]; | |
gBuffer[0].out1 = &buf[0][2][TA_BUF_PREFIX]; | |
gBuffer[0].out2 = &buf[0][3][TA_BUF_PREFIX]; | |
gBuffer[1].in = &buf[1][0][TA_BUF_PREFIX]; | |
gBuffer[1].out0 = &buf[1][1][TA_BUF_PREFIX]; | |
gBuffer[1].out1 = &buf[1][2][TA_BUF_PREFIX]; | |
gBuffer[1].out2 = &buf[1][3][TA_BUF_PREFIX]; | |
gBuffer[2].in = &buf[2][0][TA_BUF_PREFIX]; | |
gBuffer[2].out0 = &buf[2][1][TA_BUF_PREFIX]; | |
gBuffer[2].out1 = &buf[2][2][TA_BUF_PREFIX]; | |
gBuffer[2].out2 = &buf[2][3][TA_BUF_PREFIX]; | |
gBuffer[3].in = &buf[3][0][TA_BUF_PREFIX]; | |
gBuffer[3].out0 = &buf[3][1][TA_BUF_PREFIX]; | |
gBuffer[3].out1 = &buf[3][2][TA_BUF_PREFIX]; | |
gBuffer[3].out2 = &buf[3][3][TA_BUF_PREFIX]; | |
gBuffer[4].in = &buf[4][0][TA_BUF_PREFIX]; | |
gBuffer[4].out0 = &buf[4][1][TA_BUF_PREFIX]; | |
gBuffer[4].out1 = &buf[4][2][TA_BUF_PREFIX]; | |
gBuffer[4].out2 = &buf[4][3][TA_BUF_PREFIX]; | |
} | |
/* Will set some values in the buffers allowing | |
* to detect later if the function is writing | |
* out-of-bound (and to make sure the | |
* function is writing exactly the number | |
* of values it pretends to do). | |
*/ | |
void clearAllBuffers( void ) | |
{ | |
unsigned int i,j,k; | |
for( i=0; i < NB_GLOBAL_BUFFER; i++ ) | |
{ | |
for( j=0; j < TA_NB_OUT_IN; j++ ) | |
{ | |
for( k=0; k < TA_BUF_PREFIX; k++ ) | |
buf[i][j][k] = RESV_PATTERN_PREFIX; | |
for( ; k < TA_BUF_SIZE; k++ ) | |
buf[i][j][k] = RESV_PATTERN_SUFFIX; | |
} | |
} | |
} | |
void setInputBuffer( unsigned int i, const TA_Real *data, unsigned int nbElement ) | |
{ | |
unsigned int j; | |
for( j=0; j < nbElement; j++ ) | |
buf[i][0][j+TA_BUF_PREFIX] = data[j]; | |
} | |
void setInputBufferValue( unsigned int i, const TA_Real data, unsigned int nbElement ) | |
{ | |
unsigned int j; | |
for( j=0; j < nbElement; j++ ) | |
buf[i][0][j+TA_BUF_PREFIX] = data; | |
} | |
/* Check that a buffer (within a TestBuffer) is not containing | |
* NAN (or any reserved "impossible" value) within the specified | |
* range (it also checks that all out-of-bound values are untouch). | |
* | |
* Return 1 on success. | |
*/ | |
ErrorNumber checkForNAN( const TA_Real *buffer, | |
unsigned int nbElement ) | |
{ | |
unsigned int i; | |
unsigned int idx; | |
const TA_Real *theBuffer; | |
theBuffer = buffer - TA_BUF_PREFIX; | |
/* Check that the prefix are all still untouch. */ | |
for( idx=0; idx < TA_BUF_PREFIX; idx++ ) | |
{ | |
if( theBuffer[idx] != RESV_PATTERN_PREFIX ) | |
{ | |
printf( "Fail: Out of range writing in prefix buffer (%d,%f)\n", idx, theBuffer[idx] ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_0; | |
} | |
} | |
if( nbElement > MAX_NB_TEST_ELEMENT ) | |
{ | |
printf( "Fail: outNbElement is out of range 0 (%d)\n", nbElement ); | |
return TA_TEST_TFRR_NB_ELEMENT_OUT_OF_RANGE; | |
} | |
/* Check that no NAN (or reserved "impossible" value) exist | |
* in the specified range. | |
*/ | |
for( i=0; i < nbElement; i++,idx++ ) | |
{ | |
/* TODO Add back some nan/inf checking | |
if( trio_isnan(theBuffer[idx]) ) | |
{ | |
printf( "Fail: Not a number find within the data (%d,%f)\n", i, theBuffer[idx] ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_1; | |
} | |
if( trio_isinf(theBuffer[idx]) ) | |
{ | |
printf( "Fail: Not a number find within the data (%d,%f)\n", i, theBuffer[idx] ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_2; | |
}*/ | |
if( theBuffer[idx] == RESV_PATTERN_PREFIX ) | |
{ | |
printf( "Fail: Not a number find within the data (%d,%f)\n", i, theBuffer[idx] ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_3; | |
} | |
if( theBuffer[idx] == RESV_PATTERN_SUFFIX ) | |
{ | |
printf( "Fail: Not a number find within the data (%d,%f)\n", i, theBuffer[idx] ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_4; | |
} | |
} | |
/* Make sure that the remaining of the buffer is untouch. */ | |
for( ; idx < TA_BUF_SIZE; idx++ ) | |
{ | |
if( theBuffer[idx] != RESV_PATTERN_SUFFIX ) | |
{ | |
printf( "Fail: Out of range writing in suffix buffer (%d,%f)\n", idx, theBuffer[idx] ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_5; | |
} | |
idx++; | |
} | |
/* Make sure the global memory guard are untouch. */ | |
if( memoryGuard1 != RESV_PATTERN_MEMGUARD_1 ) | |
{ | |
printf( "Fail: MemoryGuard1 have been modified (%f,%f)\n", memoryGuard1, RESV_PATTERN_MEMGUARD_1 ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_6; | |
} | |
if( memoryGuard2 != RESV_PATTERN_MEMGUARD_2 ) | |
{ | |
printf( "Fail: MemoryGuard2 have been modified (%f,%f)\n", memoryGuard2, RESV_PATTERN_MEMGUARD_2 ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_7; | |
} | |
/* Everything looks good! */ | |
return TA_TEST_PASS; | |
} | |
/* Return 1 on success */ | |
ErrorNumber checkSameContent( TA_Real *buffer1, | |
TA_Real *buffer2 ) | |
{ | |
const TA_Real *theBuffer1; | |
const TA_Real *theBuffer2; | |
unsigned int i; | |
theBuffer1 = buffer1 - TA_BUF_PREFIX; | |
theBuffer2 = buffer2 - TA_BUF_PREFIX; | |
for( i=0; i < TA_BUF_SIZE; i++ ) | |
{ | |
/* TODO Add back nan/inf checking | |
(!trio_isnan(theBuffer1[i])) && | |
(!trio_isinf(theBuffer1[i])) && | |
*/ | |
if( (theBuffer1[i] != RESV_PATTERN_SUFFIX) && | |
(theBuffer1[i] != RESV_PATTERN_PREFIX) ) | |
{ | |
if(!TA_REAL_EQ( theBuffer1[i], theBuffer2[i], 0.000001)) | |
{ | |
printf( "Fail: Large difference found between two value expected identical (%f,%f,%d)\n", | |
theBuffer1[i], theBuffer2[i], i ); | |
return TA_TEST_TFRR_CHECK_SAME_CONTENT; | |
} | |
} | |
} | |
return TA_TEST_PASS; | |
} | |
ErrorNumber checkDataSame( const TA_Real *data, | |
const TA_Real *originalInput, | |
unsigned int nbElement ) | |
{ | |
unsigned int i; | |
ErrorNumber errNb; | |
errNb = checkForNAN( data, nbElement ); | |
if( errNb != TA_TEST_PASS ) | |
return errNb; | |
if( nbElement > MAX_NB_TEST_ELEMENT ) | |
{ | |
printf( "Fail: outNbElement is out of range 1 (%d)\n", nbElement ); | |
return TA_TEST_TFRR_NB_ELEMENT_OUT_OF_RANGE; | |
} | |
for( i=0; i < nbElement; i++ ) | |
{ | |
if( originalInput[i] != data[i] ) | |
{ | |
printf( "Fail: Data was wrongly modified (%f,%f,%d)\n", | |
originalInput[i], | |
data[i], i ); | |
return TA_TEST_TFRR_INPUT_HAS_BEEN_MODIFIED; | |
} | |
} | |
return TA_TEST_PASS; | |
} | |
ErrorNumber checkExpectedValue( const TA_Real *data, | |
TA_RetCode retCode, TA_RetCode expectedRetCode, | |
unsigned int outBegIdx, unsigned int expectedBegIdx, | |
unsigned int outNbElement, unsigned int expectedNbElement, | |
TA_Real oneOfTheExpectedOutReal, | |
unsigned int oneOfTheExpectedOutRealIndex ) | |
{ | |
if( retCode != expectedRetCode ) | |
{ | |
printf( "Fail: RetCode %d different than expected %d\n", retCode, expectedRetCode ); | |
return TA_TESTUTIL_TFRR_BAD_RETCODE; | |
} | |
if( retCode != TA_SUCCESS ) | |
{ | |
/* An error did occured, but it | |
* was expected. No need to go | |
* further. | |
*/ | |
return TA_TEST_PASS; | |
} | |
if( outNbElement > MAX_NB_TEST_ELEMENT ) | |
{ | |
printf( "Fail: outNbElement is out of range 2 (%d)\n", outNbElement ); | |
return TA_TEST_TFRR_NB_ELEMENT_OUT_OF_RANGE; | |
} | |
/* Make sure the range of output does not contains NAN. */ | |
/* TODO Add back nan/inf checking | |
for( i=0; i < outNbElement; i++ ) | |
{ | |
if( trio_isnan(data[i]) ) | |
{ | |
printf( "Fail: Not a number find within the data (%d,%f)\n", i, data[i] ); | |
return TA_TEST_TFRR_OVERLAP_OR_NAN_3; | |
} | |
}*/ | |
/* Verify that the expected output is there. */ | |
if( outNbElement != expectedNbElement ) | |
{ | |
printf( "Fail: outNbElement expected %d but got %d\n", | |
expectedNbElement, outNbElement ); | |
return TA_TESTUTIL_TFRR_BAD_OUTNBELEMENT; | |
} | |
if( expectedNbElement > 0 ) | |
{ | |
if( !TA_REAL_EQ( oneOfTheExpectedOutReal, data[oneOfTheExpectedOutRealIndex], 0.01 ) ) | |
{ | |
printf( "Fail: For index %d, Expected value = %f but calculate value is %f\n", | |
oneOfTheExpectedOutRealIndex, | |
oneOfTheExpectedOutReal, | |
data[oneOfTheExpectedOutRealIndex] ); | |
return TA_TESTUTIL_TFRR_BAD_CALCULATION; | |
} | |
if( expectedBegIdx != outBegIdx ) | |
{ | |
printf( "Fail: outBegIdx expected %d but got %d\n", expectedBegIdx, outBegIdx ); | |
return TA_TESTUTIL_TFRR_BAD_BEGIDX; | |
} | |
} | |
/* Succeed. */ | |
return TA_TEST_PASS; | |
} | |
ErrorNumber doRangeTest( RangeTestFunction testFunction, | |
TA_FuncUnstId unstId, | |
void *opaqueData, | |
unsigned int nbOutput, | |
unsigned int integerTolerance ) | |
{ | |
unsigned int outputNb; | |
ErrorNumber errNb; | |
/* Test all the outputs individually. */ | |
for( outputNb=0; outputNb < nbOutput; outputNb++ ) | |
{ | |
errNb = doRangeTestForOneOutput( testFunction, | |
unstId, | |
opaqueData, | |
outputNb, | |
integerTolerance ); | |
if( errNb != TA_TEST_PASS ) | |
{ | |
printf( "Failed: For output #%d of %d\n", outputNb+1, nbOutput ); | |
return errNb; | |
} | |
} | |
return TA_TEST_PASS; | |
} | |
void printRetCode( TA_RetCode retCode ) | |
{ | |
TA_RetCodeInfo retCodeInfo; | |
TA_SetRetCodeInfo( retCode, &retCodeInfo ); | |
printf( "\nFailed: ErrorCode %d=%s:[%s]\n", retCode, | |
retCodeInfo.enumStr, | |
retCodeInfo.infoStr ); | |
} | |
/**** Local functions definitions. ****/ | |
static ErrorNumber doRangeTestForOneOutput( RangeTestFunction testFunction, | |
TA_FuncUnstId unstId, | |
void *opaqueData, | |
unsigned int outputNb, | |
unsigned int integerTolerance ) | |
{ | |
TA_RetCode retCode; | |
TA_Integer refOutBeg, refOutNbElement, refLookback; | |
TA_Integer fixSize; | |
TA_Real *refBuffer; | |
TA_Integer *refBufferInt; | |
ErrorNumber errNb; | |
TA_Integer unstablePeriod, temp; | |
unsigned int outputIsInteger; | |
showFeedback(); | |
/* Caculate the whole range. This is going | |
* to be the reference for all subsequent test. | |
*/ | |
refBuffer = (TA_Real *)TA_Malloc( MAX_RANGE_SIZE * sizeof( TA_Real ) ); | |
if( !refBuffer ) | |
return TA_TESTUTIL_DRT_ALLOC_ERR; | |
refBufferInt = (TA_Integer *)TA_Malloc( MAX_RANGE_SIZE * sizeof( TA_Integer ) ); | |
if( !refBufferInt ) | |
{ | |
TA_Free( refBuffer ); | |
return TA_TESTUTIL_DRT_ALLOC_ERR; | |
} | |
if( unstId != TA_FUNC_UNST_NONE ) | |
{ | |
/* Caller wish to test for a range of unstable | |
* period values. But the reference is calculated | |
* on the whole range by keeping that unstable period | |
* to zero. | |
*/ | |
TA_SetUnstablePeriod( unstId, 0 ); | |
} | |
outputIsInteger = 0; | |
retCode = CallTestFunction( testFunction, 0, MAX_RANGE_END, refBuffer, refBufferInt, | |
&refOutBeg, &refOutNbElement, &refLookback, | |
opaqueData, outputNb, &outputIsInteger ); | |
if( retCode != TA_SUCCESS ) | |
{ | |
printf( "Fail: doRangeTest whole range failed (%d)\n", retCode ); | |
TA_Free( refBuffer ); | |
TA_Free( refBufferInt ); | |
return TA_TESTUTIL_DRT_REF_FAILED; | |
} | |
/* When calculating for the whole range, the lookback and the | |
* refOutBeg are supppose to be equal. | |
*/ | |
if( refLookback != refOutBeg ) | |
{ | |
printf( "Fail: doRangeTest refLookback != refOutBeg (%d != %d)\n", refLookback, refOutBeg ); | |
TA_Free( refBuffer ); | |
TA_Free( refBufferInt ); | |
return TA_TESTUTIL_DRT_LOOKBACK_INCORRECT; | |
} | |
temp = MAX_RANGE_SIZE-refLookback; | |
if( temp != refOutNbElement ) | |
{ | |
printf( "Fail: doRangeTest either refOutNbElement or refLookback bad (%d,%d)\n", temp, refOutNbElement ); | |
TA_Free( refBuffer ); | |
TA_Free( refBufferInt ); | |
return TA_TESTUTIL_DRT_REF_OUTPUT_INCORRECT; | |
} | |
/* Calculate each value ONE by ONE and make sure it is identical | |
* to the reference. | |
* | |
* Then repeat the test but calculate TWO by TWO and so on... | |
*/ | |
for( fixSize=1; fixSize <= MAX_RANGE_SIZE; fixSize++ ) | |
{ | |
/* When a function has an unstable period, verify some | |
* unstable period between 0 and MAX_RANGE_SIZE. | |
*/ | |
if( unstId == TA_FUNC_UNST_NONE ) | |
{ | |
errNb = doRangeTestFixSize( testFunction, opaqueData, | |
refOutBeg, refOutNbElement, refLookback, | |
refBuffer, refBufferInt, | |
unstId, fixSize, outputNb, integerTolerance ); | |
if( errNb != TA_TEST_PASS) | |
{ | |
TA_Free( refBuffer ); | |
TA_Free( refBufferInt ); | |
return errNb; | |
} | |
} | |
else | |
{ | |
for( unstablePeriod=0; unstablePeriod <= MAX_RANGE_SIZE; unstablePeriod++ ) | |
{ | |
TA_SetUnstablePeriod( unstId, unstablePeriod ); | |
errNb = doRangeTestFixSize( testFunction, opaqueData, | |
refOutBeg, refOutNbElement, refLookback, | |
refBuffer, refBufferInt, | |
unstId, fixSize, outputNb, integerTolerance ); | |
if( errNb != TA_TEST_PASS) | |
{ | |
printf( "Fail: Using unstable period %d\n", unstablePeriod ); | |
TA_Free( refBuffer ); | |
TA_Free( refBufferInt ); | |
return errNb; | |
} | |
/* Randomly skip the test of some unstable period (limit case are | |
* always tested though). | |
*/ | |
if( (unstablePeriod > 5) && (unstablePeriod < 240) ) | |
{ | |
/* Randomly skips from 0 to 239 tests. Never | |
* make unstablePeriod exceed 240. | |
*/ | |
temp = (rand() % 240); | |
unstablePeriod += temp; | |
if( unstablePeriod > 240 ) | |
unstablePeriod = 240; | |
} | |
} | |
/* Because the tests with an unstable period are very intensive | |
* and kinda repetitive, skip the test of some fixSize (limit | |
* case are always tested though). | |
*/ | |
if( (fixSize > 5) && (fixSize < 240) ) | |
{ | |
/* Randomly skips from 0 to 239 tests. Never | |
* make fixSize exceed 240. | |
*/ | |
temp = (rand() % 239); | |
fixSize += temp; | |
if( fixSize > 240 ) | |
fixSize = 240; | |
} | |
} | |
} | |
TA_Free( refBuffer ); | |
TA_Free( refBufferInt ); | |
return TA_TEST_PASS; | |
} | |
static ErrorNumber doRangeTestFixSize( RangeTestFunction testFunction, | |
void *opaqueData, | |
TA_Integer refOutBeg, | |
TA_Integer refOutNbElement, | |
TA_Integer refLookback, | |
const TA_Real *refBuffer, | |
const TA_Integer *refBufferInt, | |
TA_FuncUnstId unstId, | |
TA_Integer fixSize, | |
unsigned int outputNb, | |
unsigned int integerTolerance ) | |
{ | |
TA_RetCode retCode; | |
TA_Real *outputBuffer; | |
TA_Real val1, val2; | |
TA_Integer i, temp; | |
TA_Integer outputBegIdx, outputNbElement, lookback; | |
TA_Integer startIdx, endIdx, relativeIdx, outputSizeByOptimalLogic; | |
TA_Integer *outputBufferInt; | |
unsigned int outputIsInteger; | |
(void)refLookback; | |
/* Allocate the output buffer (+prefix and suffix memory guard). */ | |
outputBuffer = (TA_Real *)TA_Malloc( (fixSize+2) * sizeof( TA_Real ) ); | |
if( !outputBuffer ) | |
return TA_TESTUTIL_DRT_ALLOC_ERR; | |
outputBufferInt = (TA_Integer *)TA_Malloc( (fixSize+2) * sizeof( TA_Integer ) ); | |
if( !refBufferInt ) | |
{ | |
TA_Free( outputBuffer ); | |
return TA_TESTUTIL_DRT_ALLOC_ERR; | |
} | |
outputBuffer[0] = RESV_PATTERN_PREFIX; | |
outputBuffer[fixSize+1] = RESV_PATTERN_SUFFIX; | |
outputBufferInt[0] = RESV_PATTERN_PREFIX_INT; | |
outputBufferInt[fixSize+1] = RESV_PATTERN_SUFFIX_INT; | |
/* Initialize the outputs with improbable values. */ | |
for( i=1; i <= fixSize; i++ ) | |
{ | |
outputBuffer[i] = RESV_PATTERN_IMPROBABLE; | |
outputBufferInt[i] = RESV_PATTERN_IMPROBABLE_INT; | |
} | |
/* Test for a large number of possible startIdx */ | |
for( startIdx=0; startIdx <= (MAX_RANGE_SIZE-fixSize); startIdx++ ) | |
{ | |
/* Call the TA function. */ | |
endIdx = startIdx+fixSize-1; | |
retCode = CallTestFunction( testFunction, startIdx, endIdx, | |
&outputBuffer[1], &outputBufferInt[1], | |
&outputBegIdx, &outputNbElement, &lookback, | |
opaqueData, outputNb, &outputIsInteger ); | |
if( retCode != TA_SUCCESS ) | |
{ | |
/* No call shall never fail here. When the range | |
* is "out-of-range" the function shall still return | |
* TA_SUCCESS with the outNbElement equal to zero. | |
*/ | |
printf( "Fail: doRangeTestFixSize testFunction return error=(%d) (%d,%d)\n", retCode, fixSize, startIdx ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_RETCODE_ERR; | |
} | |
else | |
{ | |
/* Possible startIdx gap of the output shall be always the | |
* same regardless of the range. | |
*/ | |
if( outputNbElement == 0 ) | |
{ | |
/* Trap cases where there is no output. */ | |
if( (startIdx > lookback) || (endIdx > lookback) ) | |
{ | |
/* Whenever startIdx is greater than lookback, some data | |
* shall be return. Same idea with endIdx. | |
* | |
* Note: | |
* some output will never start at the startIdx, particularly | |
* when a TA function have multiple output. Usually, the first output | |
* will be between startIdx/endIdx and other outputs may have a "gap" | |
* from the startIdx. | |
* | |
* Example: | |
* Stochastic %K is between startIdx/endIdx, but %D output will | |
* have less data because it is a MA of %K. A gap will then | |
* exist for the %D output. | |
*/ | |
printf( "Fail: doRangeTestFixSize data missing (%d,%d,%d)\n", startIdx, endIdx, lookback ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_MISSING_DATA; | |
} | |
} | |
else | |
{ | |
/* Some output was returned. Are the returned index correct? */ | |
if( (outputBegIdx < startIdx) || (outputBegIdx > endIdx) || (outputBegIdx < refOutBeg)) | |
{ | |
printf( "Fail: doRangeTestFixSize bad outBegIdx\n" ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_BAD_OUTBEGIDX; | |
} | |
if( (outputNbElement > fixSize) || (outputNbElement > refOutNbElement) ) | |
{ | |
printf( "Fail: doRangeTestFixSize Incorrect outputNbElement\n" ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
return TA_TESTUTIL_DRT_BAD_OUTNBLEMENT; | |
} | |
/* Is the calculated lookback too high? */ | |
if( outputBegIdx < lookback ) | |
{ | |
printf( "Fail: doRangeTestFixSize Lookback calculation too high? (%d)\n", lookback ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_LOOKBACK_TOO_HIGH; | |
} | |
/* Is the output identical to the reference? */ | |
relativeIdx = outputBegIdx-refOutBeg; | |
for( i=0; i < outputNbElement; i++ ) | |
{ | |
if( outputIsInteger ) | |
{ | |
if( outputBufferInt[1+i] != refBufferInt[relativeIdx+i] ) | |
{ | |
printf( "Fail: doRangeTestFixSize diff data for idx=%d (%d,%d)\n", i, | |
outputBufferInt[1+i], refBufferInt[relativeIdx+i] ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_DATA_DIFF_INT; | |
} | |
} | |
else | |
{ | |
val1 = outputBuffer[1+i]; | |
val2 = refBuffer[relativeIdx+i]; | |
if( !dataWithinReasonableRange( val1, val2, i, unstId, integerTolerance ) ) | |
{ | |
printf( "Fail: doRangeTestFixSize diff data for idx=%d (%e,%e)\n", i, val1, val2 ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
if( val1 != 0.0 ) | |
printf( "Fail: Diff %g %%\n", ((val2-val1)/val1)*100.0 ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_DATA_DIFF; | |
} | |
} | |
/* Randomly skip the verification of some value. Limit | |
* cases are always checked though. | |
*/ | |
if( outputNbElement > 30 ) | |
{ | |
temp = outputNbElement-20; | |
if( (i > 20) && (i < temp) ) | |
{ | |
/* Randomly skips from 0 to 200 verification. | |
* Never make it skip the last 20 values. | |
*/ | |
i += (rand() % 200); | |
if( i > temp ) | |
i = temp; | |
} | |
} | |
} | |
/* Verify out-of-bound writing in the output buffer. */ | |
outputSizeByOptimalLogic = max(lookback,startIdx); | |
if( outputSizeByOptimalLogic > endIdx ) | |
outputSizeByOptimalLogic = 0; | |
else | |
outputSizeByOptimalLogic = endIdx-outputSizeByOptimalLogic+1; | |
if( (fixSize != outputNbElement) && (outputBuffer[1+outputSizeByOptimalLogic] != RESV_PATTERN_IMPROBABLE) ) | |
{ | |
printf( "Fail: doRangeTestFixSize out-of-bound output (%e)\n", outputBuffer[1+outputSizeByOptimalLogic] ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_OUT_OF_BOUND_OUT; | |
} | |
if( (fixSize != outputNbElement) && (outputBufferInt[1+outputSizeByOptimalLogic] != RESV_PATTERN_IMPROBABLE_INT) ) | |
{ | |
printf( "Fail: doRangeTestFixSize out-of-bound output (%d)\n", outputBufferInt[1+outputSizeByOptimalLogic] ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_OUT_OF_BOUND_OUT_INT; | |
} | |
/* Verify that the memory guard were preserved. */ | |
if( outputBuffer[0] != RESV_PATTERN_PREFIX ) | |
{ | |
printf( "Fail: doRangeTestFixSize bad RESV_PATTERN_PREFIX (%e)\n", outputBuffer[0] ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_BAD_PREFIX; | |
} | |
if( outputBufferInt[0] != RESV_PATTERN_PREFIX_INT ) | |
{ | |
printf( "Fail: doRangeTestFixSize bad RESV_PATTERN_PREFIX_INT (%d)\n", outputBufferInt[0] ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_BAD_PREFIX; | |
} | |
if( outputBuffer[fixSize+1] != RESV_PATTERN_SUFFIX ) | |
{ | |
printf( "Fail: doRangeTestFixSize bad RESV_PATTERN_SUFFIX (%e)\n", outputBuffer[fixSize+1] ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_BAD_SUFFIX; | |
} | |
if( outputBufferInt[fixSize+1] != RESV_PATTERN_SUFFIX_INT ) | |
{ | |
printf( "Fail: doRangeTestFixSize bad RESV_PATTERN_SUFFIX_INT (%d)\n", outputBufferInt[fixSize+1] ); | |
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize ); | |
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement ); | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TESTUTIL_DRT_BAD_SUFFIX; | |
} | |
/* Clean-up for next test. */ | |
if( outputIsInteger ) | |
{ | |
for( i=1; i <= fixSize; i++ ) | |
outputBufferInt[i] = RESV_PATTERN_IMPROBABLE_INT; | |
} | |
else | |
{ | |
for( i=1; i <= fixSize; i++ ) | |
outputBuffer[i] = RESV_PATTERN_IMPROBABLE; | |
} | |
} | |
/* Skip some startIdx at random. Limit case are still | |
* tested though. | |
*/ | |
if( (startIdx > 30) && ((startIdx+100) <= (MAX_RANGE_SIZE-fixSize)) ) | |
{ | |
/* Randomly skips from 40 to 100 tests. */ | |
temp = (rand() % 100)+40; | |
startIdx += temp; | |
} | |
} | |
/* Loop and move forward for the next startIdx to test. */ | |
} | |
TA_Free( outputBuffer ); | |
TA_Free( outputBufferInt ); | |
return TA_TEST_PASS; | |
} | |
/* This function compares two value. | |
* The value is determined to be equal | |
* if it is within a certain error range. | |
*/ | |
static int dataWithinReasonableRange( TA_Real val1, TA_Real val2, | |
unsigned int outputPosition, | |
TA_FuncUnstId unstId, | |
unsigned int integerTolerance ) | |
{ | |
TA_Real difference, tolerance, temp; | |
unsigned int val1_int, val2_int, tempInt, periodToIgnore; | |
if( integerTolerance == TA_DO_NOT_COMPARE ) | |
return 1; /* Don't compare, says that everything is fine */ | |
/* If the function does not have an unstable period, | |
* the compared value shall be identical. | |
* | |
* Because the algo may vary slightly allow for | |
* a small epsilon error because of the nature | |
* of floating point operations. | |
*/ | |
if( unstId == TA_FUNC_UNST_NONE ) | |
return TA_REAL_EQ( val1, val2, 0.000000001 ); | |
/* In the context of the TA functions, all value | |
* below 0.00001 are considered equal to zero and | |
* are considered to be equal within a reasonable range. | |
* (the percentage difference might be large, but | |
* unsignificant at that level, so no tolerance | |
* check is being done). | |
*/ | |
if( (val1 < 0.00001) && (val2 < 0.00001) ) | |
return 1; | |
/* When the function is unstable, the comparison | |
* tolerate at first a large difference. | |
* | |
* As the number of "outputPosition" is higher | |
* the tolerance is reduced. | |
* | |
* In the same way, as the unstable period | |
* increase, the tolerance is reduced (that's | |
* what the unstable period is for... reducing | |
* difference). | |
* | |
* When dealing with an unstable period, the | |
* first 100 values are ignored. | |
* | |
* Following 100, the tolerance is | |
* progressively reduced as follow: | |
* | |
* 1 == 0.5/1 == 50 % | |
* 2 == 0.5/2 == 25 % | |
* ... | |
* 100 == 0.5/100 == 0.005 % | |
* ... | |
* | |
* Overall, the following is a fair estimation: | |
* When using a unstable period of 200, you | |
* can expect the output to not vary more | |
* than 0.005 % | |
* | |
* The logic is sligthly different if the | |
* output are rounded integer, but it is | |
* the same idea. | |
* | |
* The following describe the special meaning of | |
* the integerTolerance: | |
* | |
* Value 10 -> A tolerance of 1/10 is used. | |
* | |
* Value 100 -> A tolerance of 1/100 is used. | |
* | |
* Value 1000 -> A tolerance of 1/1000 is used. | |
* | |
* Value 360 -> Useful when the output are | |
* degrees. In that case, a fix | |
* tolerance of 1 degree is used. | |
* | |
* Value TA_DO_NOT_COMPARE -> | |
* Indicate that NO COMPARISON take | |
* place. This is useful for functions | |
* that cannot be compare when changing | |
* the range (like the accumulative | |
* algorithm used for TA_AD and TA_ADOSC). | |
*/ | |
/* Some functions requires a longer unstable period. | |
* These are trap here. | |
*/ | |
switch( unstId ) | |
{ | |
case TA_FUNC_UNST_T3: | |
periodToIgnore = 200; | |
break; | |
default: | |
periodToIgnore = 100; | |
break; | |
} | |
if( integerTolerance == 1000 ) | |
{ | |
/* Check for no difference of more | |
* than 1/1000 | |
*/ | |
if( val1 > val2 ) | |
difference = (val1-val2); | |
else | |
difference = (val2-val1); | |
difference *= 1000.0; | |
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1; | |
if( temp <= periodToIgnore ) | |
{ | |
/* Pretend it is fine. */ | |
return 1; | |
} | |
else if( (int)difference > 1 ) | |
{ | |
printf( "\nFail: Value diffferent by more than 1/1000 (%f)\n", difference ); | |
return 0; | |
} | |
} | |
else if( integerTolerance == 100 ) | |
{ | |
/* Check for no difference of more | |
* than 1/1000 | |
*/ | |
if( val1 > val2 ) | |
difference = (val1-val2); | |
else | |
difference = (val2-val1); | |
difference *= 100.0; | |
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1; | |
if( temp <= periodToIgnore ) | |
{ | |
/* Pretend it is fine. */ | |
return 1; | |
} | |
else if( (int)difference > 1 ) | |
{ | |
printf( "\nFail: Value diffferent by more than 1/100 (%f)\n", difference ); | |
return 0; | |
} | |
} | |
else if( integerTolerance == 10 ) | |
{ | |
/* Check for no difference of more | |
* than 1/1000 | |
*/ | |
if( val1 > val2 ) | |
difference = (val1-val2); | |
else | |
difference = (val2-val1); | |
difference *= 10.0; | |
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1; | |
if( temp <= periodToIgnore ) | |
{ | |
/* Pretend it is fine. */ | |
return 1; | |
} | |
else if( (int)difference > 1 ) | |
{ | |
printf( "\nFail: Value diffferent by more than 1/10 (%f)\n", difference ); | |
return 0; | |
} | |
} | |
else if( integerTolerance == 360 ) | |
{ | |
/* Check for no difference of no more | |
* than 10% when the value is higher than | |
* 1 degree. | |
* | |
* Difference of less than 1 degree are not significant. | |
*/ | |
val1_int = (unsigned int)val1; | |
val2_int = (unsigned int)val2; | |
if( val1_int > val2_int ) | |
tempInt = val1_int - val2_int; | |
else | |
tempInt = val2_int - val1_int; | |
if( val1 > val2 ) | |
difference = (val1-val2)/val1; | |
else | |
difference = (val2-val1)/val2; | |
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1; | |
if( temp <= periodToIgnore ) | |
{ | |
/* Pretend it is fine. */ | |
return 1; | |
} | |
else if( (tempInt > 1) && (difference > 0.10) ) | |
{ | |
printf( "\nFail: Value diffferent by more than 10 percent over 1 degree (%d)\n", tempInt ); | |
return 0; | |
} | |
} | |
else if( integerTolerance ) | |
{ | |
/* Check that the integer part of the value | |
* is not different more than the specified | |
* integerTolerance. | |
*/ | |
val1_int = (unsigned int)val1; | |
val2_int = (unsigned int)val2; | |
if( val1_int > val2_int ) | |
tempInt = val1_int - val2_int; | |
else | |
tempInt = val2_int - val1_int; | |
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1; | |
if( temp <= periodToIgnore ) | |
{ | |
/* Pretend it is fine. */ | |
return 1; | |
} | |
else if( temp < 100 ) | |
{ | |
if( tempInt >= 3*integerTolerance ) | |
{ | |
printf( "\nFail: Value out of 3*tolerance range (%d,%d)\n", tempInt, integerTolerance ); | |
return 0; /* Value considered different */ | |
} | |
} | |
else if( temp < 150 ) | |
{ | |
if( tempInt >= 2*integerTolerance ) | |
{ | |
printf( "\nFail: Value out of 2*tolerance range (%d,%d)\n", tempInt, integerTolerance ); | |
return 0; /* Value considered different */ | |
} | |
} | |
else if( temp < 200 ) | |
{ | |
if( tempInt >= integerTolerance ) | |
{ | |
printf( "\nFail: Value out of tolerance range (%d,%d)\n", tempInt, integerTolerance ); | |
return 0; /* Value considered different */ | |
} | |
} | |
else if( tempInt >= 1 ) | |
{ | |
printf( "\nFail: Value not equal (difference is %d)\n", tempInt ); | |
return 0; /* Value considered different */ | |
} | |
} | |
else | |
{ | |
if( val1 > val2 ) | |
difference = (val1-val2)/val1; | |
else | |
difference = (val2-val1)/val2; | |
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1; | |
if( temp <= periodToIgnore ) | |
{ | |
/* Pretend it is fine. */ | |
return 1; | |
} | |
else | |
{ | |
temp -= periodToIgnore; | |
tolerance = 0.5/temp; | |
} | |
if( difference > tolerance ) | |
{ | |
printf( "\nFail: Value out of tolerance range (%g,%g)\n", difference, tolerance ); | |
return 0; /* Out of tolerance... values are not equal. */ | |
} | |
} | |
return 1; /* Value equal within tolerance. */ | |
} | |
static TA_RetCode CallTestFunction( RangeTestFunction testFunction, | |
TA_Integer startIdx, | |
TA_Integer endIdx, | |
TA_Real *outputBuffer, | |
TA_Integer *outputBufferInt, | |
TA_Integer *outBegIdx, | |
TA_Integer *outNbElement, | |
TA_Integer *lookback, | |
void *opaqueData, | |
unsigned int outputNb, | |
unsigned int *isOutputInteger ) | |
{ | |
/* Call the function and do profiling. */ | |
TA_RetCode retCode; | |
double clockDelta; | |
LARGE_INTEGER startClock; | |
LARGE_INTEGER endClock; | |
clock_t startClock; | |
clock_t endClock; | |
QueryPerformanceCounter(&startClock); | |
startClock = clock(); | |
retCode = testFunction( startIdx, | |
endIdx, | |
outputBuffer, | |
outputBufferInt, | |
outBegIdx, | |
outNbElement, | |
lookback, | |
opaqueData, | |
outputNb, | |
isOutputInteger ); | |
/* Profile only functions producing at least 20 values. */ | |
if( *outNbElement < 20 ) | |
{ | |
return retCode; | |
} | |
QueryPerformanceCounter(&endClock); | |
clockDelta = (double)((__int64)endClock.QuadPart - (__int64) startClock.QuadPart); | |
endClock = clock(); | |
clockDelta = (double)(endClock - startClock); | |
if( clockDelta <= 0 ) | |
{ | |
insufficientClockPrecision = 1; | |
} | |
else | |
{ | |
if( clockDelta > worstProfiledCall ) | |
worstProfiledCall = clockDelta; | |
timeInProfiledCall += clockDelta; | |
nbProfiledCall++; | |
} | |
return retCode; | |
} | |