#include <cstring>
#include <gtest/gtest.h>
#include <boost/program_options.hpp>
#include "clFFT.h"
#include "clFFT.version.h"
#include "test_constants.h"
#include "../client/openCL.misc.h"
#include "unicode.compatibility.h"
namespace po = boost::program_options;
size_t number_of_random_tests;
time_t random_test_parameter_seed;
float tolerance;
double rmse_tolerance;
bool verbose;
#if defined( MSVC_VER )
#if !defined( NOMINMAX )
#define NOMINMAX
#endif
#define WIN32_LEAN_AND_MEAN
#include <intrin.h>
#if defined( _WIN64 )
void inline BSF( unsigned long* index, size_t& mask )
{
_BitScanForward64( index, mask );
}
#else
void inline BSF( unsigned long* index, size_t& mask )
{
_BitScanForward( index, mask );
}
#endif
#elif defined( __GNUC__ )
void inline BSF (unsigned long * index, size_t & mask) {
*index = __builtin_ctz (mask);
}
#endif
bool suppress_output = false;
cl_device_type g_device_type = CL_DEVICE_TYPE_ALL;
cl_int g_device_id = 0;
cl_int g_platform_id = 0;
bool comparison_type = root_mean_square;
int main( int argc, char **argv )
{
#if defined( MEMORYREPORT ) && defined( _WIN32 )
TCHAR logPath[ MAX_PATH ];
::GetCurrentDirectory( MAX_PATH, logPath );
::_tcscat_s( logPath, _T( "\\MemoryReport.txt") );
HANDLE hLogFile;
hLogFile = ::CreateFile( logPath, GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
::_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW | _CRTDBG_MODE_DEBUG );
::_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW | _CRTDBG_MODE_DEBUG );
::_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
::_CrtSetReportFile( _CRT_ASSERT, hLogFile );
::_CrtSetReportFile( _CRT_ERROR, hLogFile );
::_CrtSetReportFile( _CRT_WARN, hLogFile );
int tmp = ::_CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmp |= _CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF;
::_CrtSetDbgFlag( tmp );
#endif
po::options_description desc( "clFFT Runtime Test command line options" );
desc.add_options()
( "help,h", "produces this help message" )
( "verbose,v", "print out detailed information for the tests" )
( "noVersion", "Don't print version information from the clFFT library" )
( "noInfoCL", "Don't print information from the OpenCL runtime" )
( "cpu,c", "Run tests on a CPU device" )
( "gpu,g", "Run tests on a GPU device" )
( "all,a", "Run tests on any device type (default)" )
( "platform", po::value< cl_int >( &g_platform_id )->default_value( 0 ), "Select a specific OpenCL platform id as it is reported by clinfo" )
( "device", po::value< cl_int >( &g_device_id )->default_value( 0 ), "Select a specific OpenCL device id as it is reported by clinfo" )
( "pointwise,p", "Do a pointwise comparison to determine test correctness (default: use root mean square)" )
( "tolerance,t", po::value< float >( &tolerance )->default_value( 0.001f ), "tolerance level to use when determining test pass/fail" )
( "numRandom,r", po::value< size_t >( &number_of_random_tests )->default_value( 2000 ), "number of random tests to run" )
( "seed", po::value< time_t >( &random_test_parameter_seed )->default_value( time(NULL)%1308000000 ),
"seed to use for the random test. defaults to time(NULL)" )
( "short,s", "Run radix 2 tests; no random testing" )
( "medium,m", "Run all radices; no random testing" )
;
rmse_tolerance = 0.00002;
po::variables_map vm;
po::parsed_options parsed = po::command_line_parser( argc, argv ).options( desc ).allow_unregistered( ).run( );
po::store( parsed, vm );
po::notify( vm );
std::vector< std::string > to_pass_further = po::collect_unrecognized( parsed.options, po::include_positional );
std::cout << std::endl;
size_t mutex = ((vm.count( "gpu" ) > 0) ? 1 : 0)
| ((vm.count( "cpu" ) > 0) ? 2 : 0)
| ((vm.count( "all" ) > 0) ? 4 : 0);
if ((mutex & (mutex-1)) != 0) {
terr << _T("You have selected mutually-exclusive OpenCL device options:") << std::endl;
if (vm.count ( "gpu" ) > 0) terr << _T(" gpu,g Force selection of OpenCL GPU devices only" ) << std::endl;
if (vm.count ( "cpu" ) > 0) terr << _T(" cpu,c Force selection of OpenCL CPU devices only" ) << std::endl;
if (vm.count ( "all" ) > 0) terr << _T(" all,a Force selection of all OpenCL devices (default)" ) << std::endl;
return 1;
}
if( vm.count( "gpu" ) )
{
g_device_type = CL_DEVICE_TYPE_GPU;
}
if( vm.count( "cpu" ) )
{
g_device_type = CL_DEVICE_TYPE_CPU;
}
if( vm.count( "all" ) )
{
g_device_type = CL_DEVICE_TYPE_ALL;
}
if( !vm.count( "noVersion" ) )
{
const int indent = countOf( "clFFT client API version: " );
tout << std::left << std::setw( indent ) << _T( "clFFT client API version: " )
<< clfftVersionMajor << _T( "." )
<< clfftVersionMinor << _T( "." )
<< clfftVersionPatch << std::endl;
cl_uint libMajor, libMinor, libPatch;
clfftGetVersion( &libMajor, &libMinor, &libPatch );
tout << std::left << std::setw( indent ) << _T( "clFFT runtime version: " )
<< libMajor << _T( "." )
<< libMinor << _T( "." )
<< libPatch << std::endl << std::endl;
}
if( !vm.count( "noInfoCL" ) )
{
cl_context tempContext = NULL;
cl_command_queue tempQueue = NULL;
cl_event tempEvent = NULL;
::initializeCL(g_device_type, g_device_id, g_platform_id, tempContext, true);
::cleanupCL( &tempContext, &tempQueue, 0, NULL, 0, NULL, &tempEvent );
}
if( vm.count( "help" ) )
{
std::cout << desc << std::endl;
return 0;
}
if( vm.count( "verbose" ) )
{
verbose = true;
}
else
{
verbose = false;
}
if( vm.count( "short" ) && vm.count( "medium" ) )
{
terr << _T("Options 'short' and 'medium' are mutually-exclusive. Please select only one.") << std::endl;
return 1;
}
std::vector< const char* > myArgv;
if( argc > 0 )
myArgv.push_back( *argv );
std::string userFilter;
for( int i = 1; i < argc; ++i )
{
if( vm.count( "short" ) || vm.count( "medium" ) )
{
std::string tmpStr( argv[ i ] );
std::string::size_type pos = tmpStr.find( "gtest_filter" );
if( pos == std::string::npos )
{
myArgv.push_back( argv[ i ] );
}
else
{
userFilter = argv[ i ];
userFilter.erase( 0, 15 );
}
}
else
{
myArgv.push_back( argv[ i ] );
}
}
std::string newFilter;
if( vm.count( "short" ) )
{
newFilter += "--gtest_filter=*accuracy_test_pow2*";
if( userFilter.size( ) )
{
newFilter += ":";
newFilter += userFilter;
}
myArgv.push_back( newFilter.c_str( ) );
}
if( vm.count( "medium" ) )
{
newFilter += "--gtest_filter=";
if( userFilter.size( ) )
{
newFilter += userFilter;
newFilter += ":";
}
newFilter += "-*Random*";
myArgv.push_back( newFilter.c_str( ) );
}
if( vm.count( "pointwise" ) )
{
comparison_type = pointwise_compare;
}
else
{
comparison_type = root_mean_square;
}
int myArgc = static_cast< int >( myArgv.size( ) );
std::cout << "Result comparison tolerance is " << tolerance << std::endl;
std::cout << "Result comparison RMSE relative tolerance is " << rmse_tolerance << std::endl;
::testing::InitGoogleTest( &myArgc, const_cast< char** >( &myArgv[ 0 ] ) );
return RUN_ALL_TESTS();
}