Loading src/AtomicModel/interp.h +21 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <math.h> #include <stdio.h> #include <stdlib.h> #include <vector> #include "CompilerFeatures.h" #ifdef ENABLE_STD_FUNCTION Loading Loading @@ -259,6 +260,15 @@ template <class type> void quicksort( size_t n, type *X ); /*! * @brief Subroutine to sort the elements in X * @details This function sorts the values in X using quicksort * @param X Input/Output: Points to sort */ template <class type> inline void quicksort( std::vector<type>& X ); /*! * @brief Subroutine to sort the elements in X * @details This function sorts the values in X Loading @@ -270,6 +280,17 @@ template <class type1, class type2> void quicksort( size_t n, type1 *X, type2 *Y ); /*! * @brief Subroutine to sort the elements in X * @details This function sorts the values in X * @param n The number of values in X * @param X Input/Output: Points to sort * @param Y Input/Output: Extra values to be sorted with X */ template <class type1, class type2> inline void quicksort( std::vector<type1>& X, std::vector<type2>& Y ); /*! * @brief Subroutine to sort the elements in X * @details This function sorts the values in X, storing them in Y Loading src/AtomicModel/interp.hpp +16 −1 Original line number Diff line number Diff line #ifndef included_interp_hpp #define included_interp_hpp #include "AtomicModel/interp.h" #include <iostream> #include <limits> #include <stdexcept> Loading Loading @@ -343,6 +342,22 @@ void interp::quicksort( size_t size, T1 *arr, T2 *brr ) } template <class type> inline void quicksort( std::vector<type>& X ) { quicksort(X.size(),X.data()); } template <class type1, class type2> inline void quicksort( std::vector<type1>& X, std::vector<type2>& Y ) { if ( X.size() != Y.size() ) throw std::logic_error( "Error: X.size() != Y>size()" ); quicksort(X.size(),X.data(),Y.data()); } inline void interp::sort( size_t n, const double *X, double *Y ) { // Copy the values of X Loading src/CMakeLists.txt +16 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,21 @@ INCLUDE( "${RAYTRACE_SOURCE_DIR}/macros.cmake" ) SET_COMPILER_FLAGS() # Check if we are using an MPI compiler SET( CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS} ) CHECK_CXX_SOURCE_COMPILES( "#include <mpi.h> int main(int, char**) { MPI_Init(NULL, NULL); MPI_Finalize(); }" USE_MPI ) IF ( USE_MPI ) ADD_DEFINITIONS( -DUSE_MPI ) MESSAGE( "Using MPI" ) ENDIF() # Enable OpenMP IF ( USE_OPENMP ) ADD_DEFINITIONS( -DUSE_OPENMP ) Loading Loading @@ -156,7 +171,7 @@ ADD_DISTCLEAN( libRayTrace.* null_timer CreateImage* ) # Create the library INCLUDE_DIRECTORIES( ${RAYTRACE_SOURCE_DIR} ) ADD_DEFINITIONS( -DDISABLE_WRITE_FAILED_RAYS ) SET( SOURCES RayTrace RayTraceImage.cpp RayTraceStructures.cpp utilities/RayUtilities.cpp AtomicModel/interp.cpp RayTraceImageCPU.cpp ) SET( SOURCES RayTrace RayTraceImage.cpp RayTraceStructures.cpp utilities/RayUtilities.cpp AtomicModel/interp.cpp RayTraceImageCPU.cpp CreateImageHelpers.cpp ) IF ( USE_OPENACC ) SET( SOURCES ${SOURCES} RayTraceImageOpenACC.cpp ) ENDIF() Loading src/CreateImage.cpp +37 −187 Original line number Diff line number Diff line Loading @@ -2,6 +2,9 @@ // This miniapp mimics the behavior of create_image #include "RayTrace.h" #include "MPI_helpers.h" #include "CreateImageHelpers.h" #include <cstring> #include <iostream> #include <math.h> Loading @@ -10,191 +13,18 @@ #include <string> #if defined( WIN32 ) || defined( _WIN32 ) || defined( WIN64 ) || defined( _WIN64 ) #include <windows.h> #define get_time( x ) QueryPerformanceCounter( x ) #define get_frequency( f ) QueryPerformanceFrequency( f ) #define TIME_TYPE LARGE_INTEGER #define sleep_ms Sleep inline double get_diff( TIME_TYPE start, TIME_TYPE end, TIME_TYPE f ) { return ( ( (double) ( end.QuadPart - start.QuadPart ) ) / ( (double) f.QuadPart ) ); } #else #include <sys/time.h> #define get_time( x ) gettimeofday( x, NULL ); #define get_frequency( f ) ( *f = timeval() ) #define TIME_TYPE timeval #define sleep_ms( X ) \ do { \ struct timespec ts; \ ts.tv_sec = X / 1000; \ ts.tv_nsec = ( X % 1000 ) * 1000000; \ nanosleep( &ts, NULL ); \ } while ( 0 ) inline double get_diff( TIME_TYPE start, TIME_TYPE end, TIME_TYPE ) { return ( (double) end.tv_sec - start.tv_sec ) + 1e-6 * ( (double) end.tv_usec - start.tv_usec ); } #endif #ifdef USE_KOKKOS #include <Kokkos_Core.hpp> #endif inline void fread2( void *ptr, size_t size, size_t count, FILE *fid ) { size_t N = fread( ptr, size, count, fid ); if ( N != count ) { std::cerr << "Failed to read desired count\n"; exit( -1 ); } } // Check the answer inline bool check_ans( const double *image0, const double *I_ang0, const RayTrace::create_image_struct &data ) { size_t N_image = data.euv_beam->nx * data.euv_beam->ny * data.euv_beam->nv; size_t N_ang = data.euv_beam->na * data.euv_beam->nb; double error[2] = { 0, 0 }; double norm0[2] = { 0, 0 }; double norm1[2] = { 0, 0 }; for ( size_t i = 0; i < N_image; i++ ) { error[0] += ( image0[i] - data.image[i] ) * ( image0[i] - data.image[i] ); norm0[0] += image0[i] * image0[i]; norm1[0] += data.image[i] * data.image[i]; } for ( size_t i = 0; i < N_ang; i++ ) { error[1] += ( I_ang0[i] - data.I_ang[i] ) * ( I_ang0[i] - data.I_ang[i] ); norm0[1] += I_ang0[i] * I_ang0[i]; norm1[1] += data.I_ang[i] * data.I_ang[i]; } norm0[0] = sqrt( norm0[0] ); norm0[1] = sqrt( norm0[1] ); norm1[0] = sqrt( norm1[0] ); norm1[1] = sqrt( norm1[1] ); error[0] = sqrt( error[0] ) / norm0[0]; error[1] = sqrt( error[1] ) / norm0[1]; const double tol = 5e-6; // RayTrace uses single precision for some calculations (may need to adjust to 1e-5) // bool pass = error[0]<=tol && error[1]<=tol; bool pass = ( norm0[0] - norm1[0] ) / norm0[0] <= tol && ( norm0[1] - norm1[1] ) / norm0[1] <= tol; if ( !pass ) { std::cerr << " Answers do not match:" << std::endl; std::cerr << " image: " << error[0] << " " << norm0[0] << " " << norm1[0] << std::endl; std::cerr << " I_ang: " << error[1] << " " << norm0[1] << " " << norm1[1] << std::endl; } return pass; } // Scale the input problem template <class TYPE> void scale_beam( TYPE &beam, double scale ) { const double x[2] = { beam.x[0] - 0.5 * beam.dx, beam.x[beam.nx - 1] + 0.5 * beam.dx }; const double y[2] = { beam.y[0] - 0.5 * beam.dy, beam.y[beam.ny - 1] + 0.5 * beam.dy }; const double a[2] = { beam.a[0] - 0.5 * beam.da, beam.a[beam.na - 1] + 0.5 * beam.da }; const double b[2] = { beam.b[0] - 0.5 * beam.db, beam.b[beam.nb - 1] + 0.5 * beam.db }; int nx = static_cast<int>( beam.nx * scale ); int ny = static_cast<int>( beam.ny * scale ); int na = static_cast<int>( beam.na * scale ); int nb = static_cast<int>( beam.nb * scale ); delete[] beam.x; beam.x = new double[nx]; delete[] beam.y; beam.y = new double[ny]; delete[] beam.a; beam.a = new double[na]; delete[] beam.b; beam.b = new double[nb]; beam.nx = nx; beam.dx = ( x[1] - x[0] ) / nx; beam.ny = ny; beam.dy = ( y[1] - y[0] ) / ny; beam.na = na; beam.da = ( a[1] - a[0] ) / na; beam.nb = nb; beam.db = ( b[1] - b[0] ) / nb; for ( int i = 0; i < nx; i++ ) { beam.x[i] = x[0] + ( 0.5 + i ) * beam.dx; } for ( int i = 0; i < ny; i++ ) { beam.y[i] = y[0] + ( 0.5 + i ) * beam.dy; } for ( int i = 0; i < na; i++ ) { beam.a[i] = a[0] + ( 0.5 + i ) * beam.da; } for ( int i = 0; i < nb; i++ ) { beam.b[i] = b[0] + ( 0.5 + i ) * beam.db; } } void scale_problem( RayTrace::create_image_struct &info, double scale ) { scale_beam( *const_cast<RayTrace::EUV_beam_struct *>( info.euv_beam ), pow( scale, 0.25 ) ); if ( info.seed_beam != NULL ) scale_beam( *const_cast<RayTrace::seed_beam_struct *>( info.seed_beam ), pow( scale, 0.25 ) ); } // Clas to hold options class Options { public: Options() {}; int iterations = 1; double scale = 1.0; std::vector<std::string> methods; std::vector<std::string> read_cmd( int argc, char *argv[] ) { const char *err_msg = "CreateImage called with the wrong number of arguments:\n" " CreateImage <args> file.dat\n" "Optional arguments:\n" " -methods=METHODS Comma seperated list of methods to test. Default is all availible methods\n" " cpu, threads, OpenMP, Cuda, OpenAcc, Kokkos-Serial, " "Kokkos-Thread, Kokkos-OpenMP, Kokkos-Cuda\n" " -iterations=N Number of iterations to run. Time returned will be " "the average time/iteration.\n" " -scale=factor Increate the size of the problem by ~ this factor. " "(2.0 - twice as expensive)\n" " Note: this will disable checking the answer.\n" " Note: the scale factor is only approximate.\n"; std::vector<std::string> filenames; for ( int i = 1; i < argc; i++ ) { if ( argv[i][0] == '-' ) { // Processing an argument if ( strncmp( argv[i], "-methods=", 9 ) == 0 ) { std::stringstream ss( &argv[i][9] ); std::string token; while ( std::getline( ss, token, ',' ) ) methods.push_back( token ); } else if ( strncmp( argv[i], "-iterations=", 12 ) == 0 ) { iterations = atoi( &argv[i][12] ); } else if ( strncmp( argv[i], "-scale=", 7 ) == 0 ) { scale = atof( &argv[i][7] ); } else { std::cerr << "Unknown option: " << argv[i] << std::endl; return std::vector<std::string>(); } } else { // Processing a filename filenames.push_back( argv[i] ); } } if ( filenames.empty() ) std::cerr << err_msg; return filenames; } }; // Run the tests for a single file int run_tests( const std::string& filename, const Options& options ) { if ( rank() == 0 ) printf( "\nRunning tests for %s\n\n", filename.c_str() ); // load the input file FILE *fid = fopen( filename.c_str(), "rb" ); Loading Loading @@ -259,16 +89,18 @@ int run_tests( const std::string& filename, const Options& options ) // Call create_image for each method int N_errors = 0; sleep_ms( 50 ); std::vector<double> time( methods.size() ); std::vector<std::vector<double>> time( methods.size() ); for ( size_t i = 0; i < methods.size(); i++ ) { if ( rank() == 0 ) printf( "Running %s\n", methods[i].c_str() ); TIME_TYPE start, stop, f; get_frequency( &f ); get_time( &start ); for ( int it = 0; it < options.iterations; it++ ) double start = getTime(); for ( int it = 0; it < options.iterations; it++ ) { RayTrace::create_image( &info, methods[i] ); get_time( &stop ); time[i] = get_diff( start, stop, f ); double stop = getTime(); time[i].push_back( stop - start ); start = stop; } time[i] = gatherAll( time[i] ); // Check the results if ( scale == 1.0 ) { bool pass = check_ans( image0, I_ang0, info ); Loading @@ -280,9 +112,24 @@ int run_tests( const std::string& filename, const Options& options ) info.image = NULL; info.I_ang = NULL; } printf( "\n METHOD TIME\n" ); for ( size_t i = 0; i < methods.size(); i++ ) printf( "%14s %0.3f\n", methods[i].c_str(), time[i] ); if ( rank() == 0 ) { printf( "\n METHOD Avg Min Max Std Dev\n" ); for ( size_t i = 0; i < methods.size(); i++ ) { double min = getMin( time[i] ); double max = getMax( time[i] ); double avg = getAvg( time[i] ); double dev = getDev( time[i] ); printf( "%14s %7.3f %7.3f %7.3f %7.3f\n", methods[i].c_str(), avg, min, max, dev ); if ( dev/avg > 0.10 ) { printf( " Standard deviation exceeded tolerance (10%%)\n"); N_errors++; } if ( (max-avg)/avg > 0.15 ) { printf( " Maximum runtime exceeded average by more than 15%%\n"); N_errors++; } } } // Free memory and return free( (void *) image0 ); Loading @@ -291,7 +138,7 @@ int run_tests( const std::string& filename, const Options& options ) delete info.seed_beam; delete[] info.gain; delete info.seed; return N_errors; return sumReduce(N_errors); } Loading @@ -300,6 +147,8 @@ int run_tests( const std::string& filename, const Options& options ) ******************************************************************/ int main( int argc, char *argv[] ) { // Start MPI (if used) startup( argc, argv ); // Initialize kokkos #ifdef USE_KOKKOS Loading Loading @@ -335,5 +184,6 @@ int main( int argc, char *argv[] ) #ifdef USE_KOKKOS Kokkos::finalize(); #endif shutdown(); return N_errors; } src/CreateImage.h 0 → 100644 +0 −0 Empty file added. Loading
src/AtomicModel/interp.h +21 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <math.h> #include <stdio.h> #include <stdlib.h> #include <vector> #include "CompilerFeatures.h" #ifdef ENABLE_STD_FUNCTION Loading Loading @@ -259,6 +260,15 @@ template <class type> void quicksort( size_t n, type *X ); /*! * @brief Subroutine to sort the elements in X * @details This function sorts the values in X using quicksort * @param X Input/Output: Points to sort */ template <class type> inline void quicksort( std::vector<type>& X ); /*! * @brief Subroutine to sort the elements in X * @details This function sorts the values in X Loading @@ -270,6 +280,17 @@ template <class type1, class type2> void quicksort( size_t n, type1 *X, type2 *Y ); /*! * @brief Subroutine to sort the elements in X * @details This function sorts the values in X * @param n The number of values in X * @param X Input/Output: Points to sort * @param Y Input/Output: Extra values to be sorted with X */ template <class type1, class type2> inline void quicksort( std::vector<type1>& X, std::vector<type2>& Y ); /*! * @brief Subroutine to sort the elements in X * @details This function sorts the values in X, storing them in Y Loading
src/AtomicModel/interp.hpp +16 −1 Original line number Diff line number Diff line #ifndef included_interp_hpp #define included_interp_hpp #include "AtomicModel/interp.h" #include <iostream> #include <limits> #include <stdexcept> Loading Loading @@ -343,6 +342,22 @@ void interp::quicksort( size_t size, T1 *arr, T2 *brr ) } template <class type> inline void quicksort( std::vector<type>& X ) { quicksort(X.size(),X.data()); } template <class type1, class type2> inline void quicksort( std::vector<type1>& X, std::vector<type2>& Y ) { if ( X.size() != Y.size() ) throw std::logic_error( "Error: X.size() != Y>size()" ); quicksort(X.size(),X.data(),Y.data()); } inline void interp::sort( size_t n, const double *X, double *Y ) { // Copy the values of X Loading
src/CMakeLists.txt +16 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,21 @@ INCLUDE( "${RAYTRACE_SOURCE_DIR}/macros.cmake" ) SET_COMPILER_FLAGS() # Check if we are using an MPI compiler SET( CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS} ) CHECK_CXX_SOURCE_COMPILES( "#include <mpi.h> int main(int, char**) { MPI_Init(NULL, NULL); MPI_Finalize(); }" USE_MPI ) IF ( USE_MPI ) ADD_DEFINITIONS( -DUSE_MPI ) MESSAGE( "Using MPI" ) ENDIF() # Enable OpenMP IF ( USE_OPENMP ) ADD_DEFINITIONS( -DUSE_OPENMP ) Loading Loading @@ -156,7 +171,7 @@ ADD_DISTCLEAN( libRayTrace.* null_timer CreateImage* ) # Create the library INCLUDE_DIRECTORIES( ${RAYTRACE_SOURCE_DIR} ) ADD_DEFINITIONS( -DDISABLE_WRITE_FAILED_RAYS ) SET( SOURCES RayTrace RayTraceImage.cpp RayTraceStructures.cpp utilities/RayUtilities.cpp AtomicModel/interp.cpp RayTraceImageCPU.cpp ) SET( SOURCES RayTrace RayTraceImage.cpp RayTraceStructures.cpp utilities/RayUtilities.cpp AtomicModel/interp.cpp RayTraceImageCPU.cpp CreateImageHelpers.cpp ) IF ( USE_OPENACC ) SET( SOURCES ${SOURCES} RayTraceImageOpenACC.cpp ) ENDIF() Loading
src/CreateImage.cpp +37 −187 Original line number Diff line number Diff line Loading @@ -2,6 +2,9 @@ // This miniapp mimics the behavior of create_image #include "RayTrace.h" #include "MPI_helpers.h" #include "CreateImageHelpers.h" #include <cstring> #include <iostream> #include <math.h> Loading @@ -10,191 +13,18 @@ #include <string> #if defined( WIN32 ) || defined( _WIN32 ) || defined( WIN64 ) || defined( _WIN64 ) #include <windows.h> #define get_time( x ) QueryPerformanceCounter( x ) #define get_frequency( f ) QueryPerformanceFrequency( f ) #define TIME_TYPE LARGE_INTEGER #define sleep_ms Sleep inline double get_diff( TIME_TYPE start, TIME_TYPE end, TIME_TYPE f ) { return ( ( (double) ( end.QuadPart - start.QuadPart ) ) / ( (double) f.QuadPart ) ); } #else #include <sys/time.h> #define get_time( x ) gettimeofday( x, NULL ); #define get_frequency( f ) ( *f = timeval() ) #define TIME_TYPE timeval #define sleep_ms( X ) \ do { \ struct timespec ts; \ ts.tv_sec = X / 1000; \ ts.tv_nsec = ( X % 1000 ) * 1000000; \ nanosleep( &ts, NULL ); \ } while ( 0 ) inline double get_diff( TIME_TYPE start, TIME_TYPE end, TIME_TYPE ) { return ( (double) end.tv_sec - start.tv_sec ) + 1e-6 * ( (double) end.tv_usec - start.tv_usec ); } #endif #ifdef USE_KOKKOS #include <Kokkos_Core.hpp> #endif inline void fread2( void *ptr, size_t size, size_t count, FILE *fid ) { size_t N = fread( ptr, size, count, fid ); if ( N != count ) { std::cerr << "Failed to read desired count\n"; exit( -1 ); } } // Check the answer inline bool check_ans( const double *image0, const double *I_ang0, const RayTrace::create_image_struct &data ) { size_t N_image = data.euv_beam->nx * data.euv_beam->ny * data.euv_beam->nv; size_t N_ang = data.euv_beam->na * data.euv_beam->nb; double error[2] = { 0, 0 }; double norm0[2] = { 0, 0 }; double norm1[2] = { 0, 0 }; for ( size_t i = 0; i < N_image; i++ ) { error[0] += ( image0[i] - data.image[i] ) * ( image0[i] - data.image[i] ); norm0[0] += image0[i] * image0[i]; norm1[0] += data.image[i] * data.image[i]; } for ( size_t i = 0; i < N_ang; i++ ) { error[1] += ( I_ang0[i] - data.I_ang[i] ) * ( I_ang0[i] - data.I_ang[i] ); norm0[1] += I_ang0[i] * I_ang0[i]; norm1[1] += data.I_ang[i] * data.I_ang[i]; } norm0[0] = sqrt( norm0[0] ); norm0[1] = sqrt( norm0[1] ); norm1[0] = sqrt( norm1[0] ); norm1[1] = sqrt( norm1[1] ); error[0] = sqrt( error[0] ) / norm0[0]; error[1] = sqrt( error[1] ) / norm0[1]; const double tol = 5e-6; // RayTrace uses single precision for some calculations (may need to adjust to 1e-5) // bool pass = error[0]<=tol && error[1]<=tol; bool pass = ( norm0[0] - norm1[0] ) / norm0[0] <= tol && ( norm0[1] - norm1[1] ) / norm0[1] <= tol; if ( !pass ) { std::cerr << " Answers do not match:" << std::endl; std::cerr << " image: " << error[0] << " " << norm0[0] << " " << norm1[0] << std::endl; std::cerr << " I_ang: " << error[1] << " " << norm0[1] << " " << norm1[1] << std::endl; } return pass; } // Scale the input problem template <class TYPE> void scale_beam( TYPE &beam, double scale ) { const double x[2] = { beam.x[0] - 0.5 * beam.dx, beam.x[beam.nx - 1] + 0.5 * beam.dx }; const double y[2] = { beam.y[0] - 0.5 * beam.dy, beam.y[beam.ny - 1] + 0.5 * beam.dy }; const double a[2] = { beam.a[0] - 0.5 * beam.da, beam.a[beam.na - 1] + 0.5 * beam.da }; const double b[2] = { beam.b[0] - 0.5 * beam.db, beam.b[beam.nb - 1] + 0.5 * beam.db }; int nx = static_cast<int>( beam.nx * scale ); int ny = static_cast<int>( beam.ny * scale ); int na = static_cast<int>( beam.na * scale ); int nb = static_cast<int>( beam.nb * scale ); delete[] beam.x; beam.x = new double[nx]; delete[] beam.y; beam.y = new double[ny]; delete[] beam.a; beam.a = new double[na]; delete[] beam.b; beam.b = new double[nb]; beam.nx = nx; beam.dx = ( x[1] - x[0] ) / nx; beam.ny = ny; beam.dy = ( y[1] - y[0] ) / ny; beam.na = na; beam.da = ( a[1] - a[0] ) / na; beam.nb = nb; beam.db = ( b[1] - b[0] ) / nb; for ( int i = 0; i < nx; i++ ) { beam.x[i] = x[0] + ( 0.5 + i ) * beam.dx; } for ( int i = 0; i < ny; i++ ) { beam.y[i] = y[0] + ( 0.5 + i ) * beam.dy; } for ( int i = 0; i < na; i++ ) { beam.a[i] = a[0] + ( 0.5 + i ) * beam.da; } for ( int i = 0; i < nb; i++ ) { beam.b[i] = b[0] + ( 0.5 + i ) * beam.db; } } void scale_problem( RayTrace::create_image_struct &info, double scale ) { scale_beam( *const_cast<RayTrace::EUV_beam_struct *>( info.euv_beam ), pow( scale, 0.25 ) ); if ( info.seed_beam != NULL ) scale_beam( *const_cast<RayTrace::seed_beam_struct *>( info.seed_beam ), pow( scale, 0.25 ) ); } // Clas to hold options class Options { public: Options() {}; int iterations = 1; double scale = 1.0; std::vector<std::string> methods; std::vector<std::string> read_cmd( int argc, char *argv[] ) { const char *err_msg = "CreateImage called with the wrong number of arguments:\n" " CreateImage <args> file.dat\n" "Optional arguments:\n" " -methods=METHODS Comma seperated list of methods to test. Default is all availible methods\n" " cpu, threads, OpenMP, Cuda, OpenAcc, Kokkos-Serial, " "Kokkos-Thread, Kokkos-OpenMP, Kokkos-Cuda\n" " -iterations=N Number of iterations to run. Time returned will be " "the average time/iteration.\n" " -scale=factor Increate the size of the problem by ~ this factor. " "(2.0 - twice as expensive)\n" " Note: this will disable checking the answer.\n" " Note: the scale factor is only approximate.\n"; std::vector<std::string> filenames; for ( int i = 1; i < argc; i++ ) { if ( argv[i][0] == '-' ) { // Processing an argument if ( strncmp( argv[i], "-methods=", 9 ) == 0 ) { std::stringstream ss( &argv[i][9] ); std::string token; while ( std::getline( ss, token, ',' ) ) methods.push_back( token ); } else if ( strncmp( argv[i], "-iterations=", 12 ) == 0 ) { iterations = atoi( &argv[i][12] ); } else if ( strncmp( argv[i], "-scale=", 7 ) == 0 ) { scale = atof( &argv[i][7] ); } else { std::cerr << "Unknown option: " << argv[i] << std::endl; return std::vector<std::string>(); } } else { // Processing a filename filenames.push_back( argv[i] ); } } if ( filenames.empty() ) std::cerr << err_msg; return filenames; } }; // Run the tests for a single file int run_tests( const std::string& filename, const Options& options ) { if ( rank() == 0 ) printf( "\nRunning tests for %s\n\n", filename.c_str() ); // load the input file FILE *fid = fopen( filename.c_str(), "rb" ); Loading Loading @@ -259,16 +89,18 @@ int run_tests( const std::string& filename, const Options& options ) // Call create_image for each method int N_errors = 0; sleep_ms( 50 ); std::vector<double> time( methods.size() ); std::vector<std::vector<double>> time( methods.size() ); for ( size_t i = 0; i < methods.size(); i++ ) { if ( rank() == 0 ) printf( "Running %s\n", methods[i].c_str() ); TIME_TYPE start, stop, f; get_frequency( &f ); get_time( &start ); for ( int it = 0; it < options.iterations; it++ ) double start = getTime(); for ( int it = 0; it < options.iterations; it++ ) { RayTrace::create_image( &info, methods[i] ); get_time( &stop ); time[i] = get_diff( start, stop, f ); double stop = getTime(); time[i].push_back( stop - start ); start = stop; } time[i] = gatherAll( time[i] ); // Check the results if ( scale == 1.0 ) { bool pass = check_ans( image0, I_ang0, info ); Loading @@ -280,9 +112,24 @@ int run_tests( const std::string& filename, const Options& options ) info.image = NULL; info.I_ang = NULL; } printf( "\n METHOD TIME\n" ); for ( size_t i = 0; i < methods.size(); i++ ) printf( "%14s %0.3f\n", methods[i].c_str(), time[i] ); if ( rank() == 0 ) { printf( "\n METHOD Avg Min Max Std Dev\n" ); for ( size_t i = 0; i < methods.size(); i++ ) { double min = getMin( time[i] ); double max = getMax( time[i] ); double avg = getAvg( time[i] ); double dev = getDev( time[i] ); printf( "%14s %7.3f %7.3f %7.3f %7.3f\n", methods[i].c_str(), avg, min, max, dev ); if ( dev/avg > 0.10 ) { printf( " Standard deviation exceeded tolerance (10%%)\n"); N_errors++; } if ( (max-avg)/avg > 0.15 ) { printf( " Maximum runtime exceeded average by more than 15%%\n"); N_errors++; } } } // Free memory and return free( (void *) image0 ); Loading @@ -291,7 +138,7 @@ int run_tests( const std::string& filename, const Options& options ) delete info.seed_beam; delete[] info.gain; delete info.seed; return N_errors; return sumReduce(N_errors); } Loading @@ -300,6 +147,8 @@ int run_tests( const std::string& filename, const Options& options ) ******************************************************************/ int main( int argc, char *argv[] ) { // Start MPI (if used) startup( argc, argv ); // Initialize kokkos #ifdef USE_KOKKOS Loading Loading @@ -335,5 +184,6 @@ int main( int argc, char *argv[] ) #ifdef USE_KOKKOS Kokkos::finalize(); #endif shutdown(); return N_errors; }