// // main.c // BulletTest // // Copyright (c) 2011 Apple Inc. // #include #ifdef __APPLE__ #include #endif //__APPLE__ #include #include #include #include "main.h" #include "Utils.h" #include "TestList.h" #include "LinearMath/btScalar.h" #if defined (BT_USE_NEON) || defined (BT_USE_SSE_IN_API) #ifdef _WIN32 #define strcasecmp _stricmp #define basename(A) A #endif #define EXIT_NO_ERROR INT_MIN //int gReportNanoseconds = 0; // in Utils.c int gReportAverageTimes = 0; int gExitOnError = 0; char *gFullPath = NULL; const char *gAppName = NULL; int gArgc; const char **gArgv; typedef struct TestNode { struct TestNode *next; const char *name; }TestNode; TestNode *gNodeList = NULL; static int ParseArgs( int argc, const char *argv[] ); static void PrintUsage( void ); static int Init( void ); static void ListTests(void ); const char *gArch = #ifdef __i386__ "i386"; #elif defined __x86_64__ "x86_64"; #elif defined __arm__ "arm"; #elif defined _WIN64 "win64"; #elif defined _WIN32 "win32"; #else #error unknown arch #endif #include int main (int argc, const char * argv[]) { // Enable just one test programatically (instead of command-line param) // TestNode *node = (TestNode*) malloc( sizeof( TestNode ) ); // node->name = "btDbvt"; // node->next = 0; // gNodeList = node; srand(0.f); int numPassedTests=0; int numFailedTests= 0; int err; // Parse arguments. Build gNodeList. if( (err = ParseArgs( argc, argv ) ) ) { if( EXIT_NO_ERROR == err ) return 0; PrintUsage(); return err; } printf("Arch: %s\n", gArch ); if( gReportAverageTimes ) printf( "Reporting average times.\n" ); else printf( "Reporting best times.\n" ); // Set a few things up if( (err = Init() )) { printf( "Init failed.\n" ); return err; } if( NULL == gNodeList ) { // test everything printf( "No function list found. Testing everything...\n" ); size_t i; for( i = 0; NULL != gTestList[i].test_func; i++ ) { printf( "\n----------------------------------------------\n" ); printf( "Testing %s:\n", gTestList[i].name ); printf( "----------------------------------------------\n" ); uint64_t startTime = ReadTicks(); int local_error = gTestList[i].test_func(); uint64_t currentTime = ReadTicks() - startTime; if( local_error ) { numFailedTests++; printf( "*** %s test failed with error: %d\n", gTestList[i].name, local_error ); if( gExitOnError ) return local_error; if( 0 == err ) err = local_error; } else { numPassedTests++; printf("%s Passed.\t\t\t(%2.2gs)\n", gTestList[i].name, TicksToSeconds(currentTime)); } } } else { // test just the list while( NULL != gNodeList ) { TestNode *currentNode = gNodeList; gNodeList = gNodeList->next; // Find the test with that name size_t i; for( i = 0; NULL != gTestList[i].test_func; i++ ) if( 0 == strcasecmp( currentNode->name, gTestList[i].name ) ) break; if( NULL != gTestList[i].test_func ) { printf( "\n----------------------------------------------\n" ); printf( "Testing %s:\n", gTestList[i].name ); printf( "----------------------------------------------\n" ); uint64_t startTime = ReadTicks(); int local_error = gTestList[i].test_func(); uint64_t currentTime = ReadTicks() - startTime; if( local_error ) { numFailedTests++; printf( "*** %s test failed with error: %d\n", gTestList[i].name, local_error ); if( gExitOnError ) return local_error; if( 0 == err ) err = local_error; } else { numPassedTests++; printf("%s Passed.\t\t\t(%2.2gs)\n", gTestList[i].name, TicksToSeconds(currentTime)); } } else { printf( "\n***Error: Test name \"%s\" not found! Skipping.\n", currentNode->name ); err = -1; if( gExitOnError ) return -1; } free( currentNode ); } } printf( "\n----------------------------------------------\n" ); printf("numPassedTests = %d, numFailedTests = %d\n",numPassedTests,numFailedTests); free(gFullPath); return err; } static int Init( void ) { // init the timer TicksToCycles(0); return 0; } static int ParseArgs( int argc, const char *argv[] ) { int listTests = 0; TestNode *list = NULL; gArgc = argc; gArgv = argv; gFullPath = (char*)malloc( strlen(argv[0]) + 1); strcpy(gFullPath, argv[0]); gAppName = basename( gFullPath ); if( NULL == gAppName ) gAppName = ""; printf( "%s ", gAppName ); int skipremaining=0; size_t i; for( i = 1; i < argc; i++ ) { const char *arg = argv[i]; printf( "\t%s", arg ); if( arg[0] == '-' ) { arg++; while( arg[0] != '\0' ) { int stop = 0; switch( arg[0] ) { case 'a': gReportAverageTimes ^= 1; break; case 'e': gExitOnError ^= 1; break; case 'h': PrintUsage(); return EXIT_NO_ERROR; case 'l': listTests ^= 1; return EXIT_NO_ERROR; case 's': gReportNanoseconds ^= 1; break; case ' ': stop = 1; break; case 'N'://ignore the -NSDocumentRevisionsDebugMode argument from XCode 4.3.2 skipremaining = 1; stop = 1; break; default: printf( "\nError: Unknown flag \'%c\'\n", arg[0] ); return -1; } if( stop ) break; arg++; } } else { // add function name to the list TestNode *node = (TestNode*) malloc( sizeof( TestNode ) ); node->name = arg; node->next = list; list = node; } if (skipremaining) break; } // reverse the list of test names, and stick on gNodeList while( list ) { TestNode *node = list; TestNode *next = node->next; node->next = gNodeList; gNodeList = node; list = next; } printf( "\n" ); if( listTests ) ListTests(); return 0; } static void PrintUsage( void ) { printf("\nUsage:\n" ); printf("%s: <-aehls> ", gAppName); printf("Options:\n"); printf("\t-a\tToggle report average times vs. best times. (Default: best times)\n"); printf("\t-e\tToggle exit immediately on error behavior. (Default: off)\n"); printf("\t-h\tPrint this message.\n"); printf("\t-l\tToggle list available test names. (Default: off)\n"); printf("\t-s\tToggle report times in cycles or nanoseconds. (Default: cycles)\n\n"); printf("\tOptions may be followed by one or more test names. If no test names \n" ); printf("\tare provided, then all tests are run.\n\n"); } static void ListTests(void ) { size_t i; printf("\nTests:\n"); for( i = 0; NULL != gTestList[i].test_func; i++ ) { printf( "%19s", gTestList[i].name ); if( NULL != gTestList[i].test_func ) printf( "," ); if( 3 == (i&3) ) printf( "\n" ); } } #else #include int main(int argc, char* argv[]) { printf("error: no SIMD enabled through BT_USE_NEON or BT_USE_SSE_IN_API \n(enable in LinearMath/btScalar.h or through build system)\n"); return 0; } #endif