#ifdef WIN32
#include "windows.h"
#else
#include "time.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "ta_test_priv.h"
extern int doExtensiveProfiling;
extern double gDataOpen[];
extern double gDataHigh[];
extern double gDataLow[];
extern double gDataClose[];
extern int nbProfiledCall;
extern double timeInProfiledCall;
extern double worstProfiledCall;
extern int insufficientClockPrecision;
typedef enum
{
PROFILING_10000,
PROFILING_8000,
PROFILING_5000,
PROFILING_2000,
PROFILING_1000,
PROFILING_500,
PROFILING_100
} ProfilingType;
static ErrorNumber testLookback(TA_ParamHolder *paramHolder );
static ErrorNumber test_default_calls(void);
static ErrorNumber callWithDefaults( const char *funcName,
const double *input,
const int *input_int, int size );
static ErrorNumber callAndProfile( const char *funcName, ProfilingType type );
static double inputNegData[100];
static double inputZeroData[100];
static double inputRandFltEpsilon[100];
static double inputRandDblEpsilon[100];
static double inputRandomData[2000];
static int inputNegData_int[100];
static int inputZeroData_int[100];
static int inputRandFltEpsilon_int[100];
static int inputRandDblEpsilon_int[100];
static int inputRandomData_int[2000];
static double output[10][2000];
static int output_int[10][2000];
ErrorNumber test_abstract( void )
{
ErrorNumber retValue;
TA_RetCode retCode;
TA_ParamHolder *paramHolder;
const TA_FuncHandle *handle;
int i;
const char *xmlArray;
printf( "Testing Abstract interface\n" );
retValue = allocLib();
if( retValue != TA_TEST_PASS )
return retValue;
retCode = TA_GetFuncHandle( "STOCH", &handle );
if( retCode != TA_SUCCESS )
{
printf( "Can't get the function handle [%d]\n", retCode );
return TA_ABS_TST_FAIL_GETFUNCHANDLE;
}
retCode = TA_ParamHolderAlloc( handle, ¶mHolder );
if( retCode != TA_SUCCESS )
{
printf( "Can't allocate the param holder [%d]\n", retCode );
return TA_ABS_TST_FAIL_PARAMHOLDERALLOC;
}
retValue = testLookback(paramHolder);
if( retValue != TA_SUCCESS )
{
printf( "testLookback() failed [%d]\n", retValue );
TA_ParamHolderFree( paramHolder );
return retValue;
}
retCode = TA_ParamHolderFree( paramHolder );
if( retCode != TA_SUCCESS )
{
printf( "TA_ParamHolderFree failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_PARAMHOLDERFREE;
}
retValue = freeLib();
if( retValue != TA_TEST_PASS )
return retValue;
retValue = allocLib();
if( retValue != TA_TEST_PASS )
return retValue;
retValue = test_default_calls();
if( retValue != TA_TEST_PASS )
{
printf( "TA-Abstract default call failed\n" );
return retValue;
}
retValue = freeLib();
if( retValue != TA_TEST_PASS )
return retValue;
xmlArray = TA_FunctionDescriptionXML();
for( i=0; i < 1000000; i++ )
{
if( xmlArray[i] == 0x0 )
break;
}
if( i < 500)
{
printf( "TA_FunctionDescriptionXML failed. Size too small.\n" );
return TA_ABS_TST_FAIL_FUNCTION_DESC_SMALL;
}
if( i == 1000000 )
{
printf( "TA_FunctionDescriptionXML failed. Size too large (missing null?).\n" );
return TA_ABS_TST_FAIL_FUNCTION_DESC_LARGE;
}
return TA_TEST_PASS;
}
static ErrorNumber testLookback( TA_ParamHolder *paramHolder )
{
TA_RetCode retCode;
int lookback;
retCode = TA_SetOptInputParamInteger( paramHolder, 0, 3 );
if( retCode != TA_SUCCESS )
{
printf( "TA_SetOptInputParamInteger call failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_OPTINPUTPARAMINTEGER;
}
retCode = TA_SetOptInputParamInteger( paramHolder, 1, 4 );
if( retCode != TA_SUCCESS )
{
printf( "TA_SetOptInputParamInteger call failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_OPTINPUTPARAMINTEGER;
}
retCode = TA_SetOptInputParamInteger( paramHolder, 2, (TA_Integer)TA_MAType_SMA );
if( retCode != TA_SUCCESS )
{
printf( "TA_SetOptInputParamInteger call failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_OPTINPUTPARAMINTEGER;
}
retCode = TA_SetOptInputParamInteger( paramHolder, 3, 4 );
if( retCode != TA_SUCCESS )
{
printf( "TA_SetOptInputParamInteger call failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_OPTINPUTPARAMINTEGER;
}
retCode = TA_SetOptInputParamInteger( paramHolder, 4, (TA_Integer)TA_MAType_SMA );
if( retCode != TA_SUCCESS )
{
printf( "TA_SetOptInputParamInteger call failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_OPTINPUTPARAMINTEGER;
}
retCode = TA_GetLookback(paramHolder,&lookback);
if( retCode != TA_SUCCESS )
{
printf( "TA_GetLookback failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_GETLOOKBACK_CALL_1;
}
if( lookback != 8 )
{
printf( "TA_GetLookback failed [%d != 8]\n", lookback );
return TA_ABS_TST_FAIL_GETLOOKBACK_1;
}
retCode = TA_SetOptInputParamInteger( paramHolder, 3, 3 );
if( retCode != TA_SUCCESS )
{
printf( "TA_SetOptInputParamInteger call failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_OPTINPUTPARAMINTEGER;
}
retCode = TA_GetLookback(paramHolder,&lookback);
if( retCode != TA_SUCCESS )
{
printf( "TA_GetLookback failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_GETLOOKBACK_CALL_2;
}
if( lookback != 7 )
{
printf( "TA_GetLookback failed [%d != 7]\n", lookback );
return TA_ABS_TST_FAIL_GETLOOKBACK_2;
}
return TA_TEST_PASS;
}
static int isMath( const TA_FuncInfo *funcInfo )
{
int notMath;
notMath = (strlen(funcInfo->group) < 4) ||
!((tolower(funcInfo->group[0]) == 'm') &&
(tolower(funcInfo->group[1]) == 'a') &&
(tolower(funcInfo->group[2]) == 't') &&
(tolower(funcInfo->group[3]) == 'h'));
return !notMath;
}
#if 0#endif
static void testDefault( const TA_FuncInfo *funcInfo, void *opaqueData )
{
static int nbFunctionDone = 0;
ErrorNumber *errorNumber;
errorNumber = (ErrorNumber *)opaqueData;
if( *errorNumber != TA_TEST_PASS )
return;
#define CALL(x) { \
*errorNumber = callWithDefaults( funcInfo->name, x, x##_int, sizeof(x)/sizeof(double) ); \
if( *errorNumber != TA_TEST_PASS ) { \
printf( "Failed for [%s][%s]\n", funcInfo->name, #x ); \
return; \
} \
}
if( !isMath(funcInfo) )
{
CALL( inputNegData );
CALL( inputZeroData );
CALL( inputRandFltEpsilon );
CALL( inputRandDblEpsilon );
}
CALL( inputRandomData );
#undef CALL
#define CALL(x) { \
*errorNumber = callAndProfile( funcInfo->name, x ); \
if( *errorNumber != TA_TEST_PASS ) { \
printf( "Failed for [%s][%s]\n", funcInfo->name, #x ); \
return; \
} \
}
if( doExtensiveProfiling )
{
nbFunctionDone++;
printf( "%s ", funcInfo->name );
CALL( PROFILING_100 );
CALL( PROFILING_500 );
CALL( PROFILING_1000 );
CALL( PROFILING_2000 );
CALL( PROFILING_5000 );
CALL( PROFILING_8000 );
CALL( PROFILING_10000 );
printf( "\n" );
}
}
static ErrorNumber callWithDefaults( const char *funcName, const double *input, const int *input_int, int size )
{
TA_ParamHolder *paramHolder;
const TA_FuncHandle *handle;
const TA_FuncInfo *funcInfo;
const TA_InputParameterInfo *inputInfo;
const TA_OutputParameterInfo *outputInfo;
TA_RetCode retCode;
unsigned int i;
int j;
int outBegIdx, outNbElement, lookback;
retCode = TA_GetFuncHandle( funcName, &handle );
if( retCode != TA_SUCCESS )
{
printf( "Can't get the function handle [%d]\n", retCode );
return TA_ABS_TST_FAIL_GETFUNCHANDLE;
}
retCode = TA_ParamHolderAlloc( handle, ¶mHolder );
if( retCode != TA_SUCCESS )
{
printf( "Can't allocate the param holder [%d]\n", retCode );
return TA_ABS_TST_FAIL_PARAMHOLDERALLOC;
}
TA_GetFuncInfo( handle, &funcInfo );
for( i=0; i < funcInfo->nbInput; i++ )
{
TA_GetInputParameterInfo( handle, i, &inputInfo );
switch(inputInfo->type)
{
case TA_Input_Price:
TA_SetInputParamPricePtr( paramHolder, i,
inputInfo->flags&TA_IN_PRICE_OPEN?input:NULL,
inputInfo->flags&TA_IN_PRICE_HIGH?input:NULL,
inputInfo->flags&TA_IN_PRICE_LOW?input:NULL,
inputInfo->flags&TA_IN_PRICE_CLOSE?input:NULL,
inputInfo->flags&TA_IN_PRICE_VOLUME?input:NULL, NULL );
break;
case TA_Input_Real:
TA_SetInputParamRealPtr( paramHolder, i, input );
break;
case TA_Input_Integer:
TA_SetInputParamIntegerPtr( paramHolder, i, input_int );
break;
}
}
for( i=0; i < funcInfo->nbOutput; i++ )
{
TA_GetOutputParameterInfo( handle, i, &outputInfo );
switch(outputInfo->type)
{
case TA_Output_Real:
TA_SetOutputParamRealPtr(paramHolder,i,&output[i][0]);
for( j=0; j < 2000; j++ )
output[i][j] = TA_REAL_MIN;
break;
case TA_Output_Integer:
TA_SetOutputParamIntegerPtr(paramHolder,i,&output_int[i][0]);
for( j=0; j < 2000; j++ )
output_int[i][j] = TA_INTEGER_MIN;
break;
}
}
retCode = TA_CallFunc(paramHolder,0,size-1,&outBegIdx,&outNbElement);
if( retCode != TA_SUCCESS )
{
printf( "TA_CallFunc() failed zero data test [%d]\n", retCode );
TA_ParamHolderFree( paramHolder );
return TA_ABS_TST_FAIL_CALLFUNC_1;
}
retCode = TA_GetLookback( paramHolder, &lookback );
if( retCode != TA_SUCCESS )
{
printf( "TA_GetLookback() failed zero data test [%d]\n", retCode );
TA_ParamHolderFree( paramHolder );
return TA_ABS_TST_FAIL_CALLFUNC_2;
}
if( outBegIdx != lookback )
{
printf( "TA_GetLookback() != outBegIdx [%d != %d]\n", lookback, outBegIdx );
TA_ParamHolderFree( paramHolder );
return TA_ABS_TST_FAIL_CALLFUNC_3;
}
retCode = TA_CallFunc(paramHolder,0,0,&outBegIdx,&outNbElement);
if( retCode != TA_SUCCESS )
{
printf( "TA_CallFunc() failed data test 4 [%d]\n", retCode );
TA_ParamHolderFree( paramHolder );
return TA_ABS_TST_FAIL_CALLFUNC_4;
}
if( outBegIdx != 0 )
{
printf( "failed outBegIdx=%d when startIdx==endIdx==0\n", outBegIdx );
TA_ParamHolderFree( paramHolder );
return TA_ABS_TST_FAIL_STARTEND_ZERO;
}
retCode = TA_ParamHolderFree( paramHolder );
if( retCode != TA_SUCCESS )
{
printf( "TA_ParamHolderFree failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_PARAMHOLDERFREE;
}
return TA_TEST_PASS;
}
static ErrorNumber test_default_calls(void)
{
ErrorNumber errNumber;
unsigned int i;
unsigned int sign;
double tempDouble;
errNumber = TA_TEST_PASS;
for( i=0; i < sizeof(inputNegData)/sizeof(double); i++ )
{
inputNegData[i] = -((double)((int)i));
inputNegData_int[i] = -(int)i;
}
for( i=0; i < sizeof(inputZeroData)/sizeof(double); i++ )
{
inputZeroData[i] = 0.0;
inputZeroData_int[i] = (int)inputZeroData[i];
}
for( i=0; i < sizeof(inputRandomData)/sizeof(double); i++ )
{
tempDouble = (double)rand() / ((double)(RAND_MAX)+(double)(1));
while( (tempDouble <= 0.0) || (tempDouble >= 1.0) )
{
tempDouble = (double)rand() / ((double)(RAND_MAX)+(double)(1));
}
inputRandomData[i] = tempDouble;
inputRandomData_int[i] = (int)inputRandomData[i];
}
for( i=0; i < sizeof(inputRandFltEpsilon)/sizeof(double); i++ )
{
sign= (unsigned int)rand()%2;
inputRandFltEpsilon[i] = (sign?1.0:-1.0)*(FLT_EPSILON);
inputRandFltEpsilon_int[i] = sign?TA_INTEGER_MIN:TA_INTEGER_MAX;
}
for( i=0; i < sizeof(inputRandFltEpsilon)/sizeof(double); i++ )
{
sign= (unsigned int)rand()%2;
inputRandFltEpsilon[i] = (sign?1.0:-1.0)*(DBL_EPSILON);
inputRandFltEpsilon_int[i] = sign?1:-1;
}
if( doExtensiveProfiling )
{
printf( "\n[PROFILING START]\n" );
}
TA_ForEachFunc( testDefault, &errNumber );
if( doExtensiveProfiling )
{
printf( "[PROFILING END]\n" );
}
return errNumber;
}
static ErrorNumber callAndProfile( const char *funcName, ProfilingType type )
{
TA_ParamHolder *paramHolder;
const TA_FuncHandle *handle;
const TA_FuncInfo *funcInfo;
const TA_InputParameterInfo *inputInfo;
const TA_OutputParameterInfo *outputInfo;
TA_RetCode retCode;
int h, i, j, k;
int outBegIdx, outNbElement;
int nbInnerLoop, nbOuterLoop;
int stepSize;
int inputSize;
#ifdef WIN32
LARGE_INTEGER startClock;
LARGE_INTEGER endClock;
#else
clock_t startClock;
clock_t endClock;
#endif
double clockDelta;
int nbProfiledCallLocal;
double timeInProfiledCallLocal;
double worstProfiledCallLocal;
nbProfiledCallLocal = 0;
timeInProfiledCallLocal = 0.0;
worstProfiledCallLocal = 0.0;
nbInnerLoop = nbOuterLoop = stepSize = inputSize = 0;
switch( type )
{
case PROFILING_10000:
nbInnerLoop = 1;
nbOuterLoop = 100;
stepSize = 10000;
inputSize = 10000;
break;
case PROFILING_8000:
nbInnerLoop = 2;
nbOuterLoop = 50;
stepSize = 2000;
inputSize = 8000;
break;
case PROFILING_5000:
nbInnerLoop = 2;
nbOuterLoop = 50;
stepSize = 5000;
inputSize = 5000;
break;
case PROFILING_2000:
nbInnerLoop = 5;
nbOuterLoop = 20;
stepSize = 2000;
inputSize = 2000;
break;
case PROFILING_1000:
nbInnerLoop = 10;
nbOuterLoop = 10;
stepSize = 1000;
inputSize = 1000;
break;
case PROFILING_500:
nbInnerLoop = 20;
nbOuterLoop = 5;
stepSize = 500;
inputSize = 500;
break;
case PROFILING_100:
nbInnerLoop = 100;
nbOuterLoop = 1;
stepSize = 100;
inputSize = 100;
break;
}
retCode = TA_GetFuncHandle( funcName, &handle );
if( retCode != TA_SUCCESS )
{
printf( "Can't get the function handle [%d]\n", retCode );
return TA_ABS_TST_FAIL_GETFUNCHANDLE;
}
retCode = TA_ParamHolderAlloc( handle, ¶mHolder );
if( retCode != TA_SUCCESS )
{
printf( "Can't allocate the param holder [%d]\n", retCode );
return TA_ABS_TST_FAIL_PARAMHOLDERALLOC;
}
TA_GetFuncInfo( handle, &funcInfo );
for( i=0; i < (int)funcInfo->nbOutput; i++ )
{
TA_GetOutputParameterInfo( handle, i, &outputInfo );
switch(outputInfo->type)
{
case TA_Output_Real:
TA_SetOutputParamRealPtr(paramHolder,i,&output[i][0]);
for( j=0; j < 2000; j++ )
output[i][j] = TA_REAL_MIN;
break;
case TA_Output_Integer:
TA_SetOutputParamIntegerPtr(paramHolder,i,&output_int[i][0]);
for( j=0; j < 2000; j++ )
output_int[i][j] = TA_INTEGER_MIN;
break;
}
}
for( h=0; h < 2; h++ )
{
for( i=0; i < nbOuterLoop; i++ )
{
for( j=0; j < nbInnerLoop; j++ )
{
for( k=0; k < (int)funcInfo->nbInput; k++ )
{
TA_GetInputParameterInfo( handle, k, &inputInfo );
switch(inputInfo->type)
{
case TA_Input_Price:
TA_SetInputParamPricePtr( paramHolder, k,
inputInfo->flags&TA_IN_PRICE_OPEN?&gDataOpen[j*stepSize]:NULL,
inputInfo->flags&TA_IN_PRICE_HIGH?&gDataHigh[j*stepSize]:NULL,
inputInfo->flags&TA_IN_PRICE_LOW?&gDataLow[j*stepSize]:NULL,
inputInfo->flags&TA_IN_PRICE_CLOSE?&gDataClose[j*stepSize]:NULL,
inputInfo->flags&TA_IN_PRICE_VOLUME?&gDataClose[j*stepSize]:NULL, NULL );
break;
case TA_Input_Real:
TA_SetInputParamRealPtr( paramHolder, k, &gDataClose[j*stepSize] );
break;
case TA_Input_Integer:
printf( "\nError: Integer input not yet supported for profiling.\n" );
return TA_ABS_TST_FAIL_CALLFUNC_1;
}
}
#ifdef WIN32
QueryPerformanceCounter(&startClock);
#else
startClock = clock();
#endif
retCode = TA_CallFunc(paramHolder,0,inputSize-1,&outBegIdx,&outNbElement);
if( retCode != TA_SUCCESS )
{
printf( "TA_CallFunc() failed zero data test [%d]\n", retCode );
TA_ParamHolderFree( paramHolder );
return TA_ABS_TST_FAIL_CALLFUNC_1;
}
#ifdef WIN32
QueryPerformanceCounter(&endClock);
clockDelta = (double)((__int64)endClock.QuadPart - (__int64) startClock.QuadPart);
#else
endClock = clock();
clockDelta = (double)(endClock - startClock);
#endif
if( clockDelta <= 0 )
{
printf( "Error: Insufficient timer precision to perform benchmarking on this platform.\n" );
return TA_ABS_TST_FAIL_CALLFUNC_1;
}
else
{
if( clockDelta > worstProfiledCall )
worstProfiledCall = clockDelta;
timeInProfiledCall += clockDelta;
nbProfiledCall++;
}
if( clockDelta > worstProfiledCallLocal )
worstProfiledCallLocal = clockDelta;
timeInProfiledCallLocal += clockDelta;
nbProfiledCallLocal++;
}
}
}
printf( "%g ", (timeInProfiledCallLocal-worstProfiledCallLocal)/(double)(nbProfiledCallLocal-1));
retCode = TA_ParamHolderFree( paramHolder );
if( retCode != TA_SUCCESS )
{
printf( "TA_ParamHolderFree failed [%d]\n", retCode );
return TA_ABS_TST_FAIL_PARAMHOLDERFREE;
}
return TA_TEST_PASS;
}