// // Simple MOAB ErrorInfo benchmark test program // Compile using: // -std=gnu++11 -O3 -ftree-vectorize moab_errtest.cpp -o moab_errtest // Usage: // ./moab_errtest // #include #include #include #include //#define RANDOMIZE_FAILURES #define FAILURE_RATE 0 //#define PRINT_FAILURES #define USE_CHRONO // #define NO_RECURSION #ifdef USE_CHRONO #include #else #include #endif #ifdef RANDOMIZE_FAILURES #include std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution<> dis(0.0, 1.0); #endif using namespace std; enum ErrorCode { MB_SUCCESS = 0, MB_FAILURE = 1 }; class ErrorInfo1 { ErrorCode mErrorCode; public: ErrorInfo1(ErrorCode err_code = MB_FAILURE) : mErrorCode(err_code) { } ErrorInfo1(const ErrorInfo1& err_info) : mErrorCode(err_info.mErrorCode) { } ~ErrorInfo1() { #ifdef PRINT_FAILURES if (mErrorCode == MB_FAILURE) std::cerr << "ErrorInfo1 Failed" << std::endl; #endif } }; class ErrorInfo2 { ErrorCode mErrorCode; std::ostringstream mErrorMsg; public: ErrorInfo2(ErrorCode err_code = MB_FAILURE, const char* err_msg = "") : mErrorCode(err_code), mErrorMsg(err_msg) { } ErrorInfo2(const ErrorInfo2& err_info) : mErrorCode(err_info.mErrorCode) { mErrorMsg << err_info.mErrorMsg.str(); // Cannot use constructor of ostringstream } ~ErrorInfo2() { #ifdef PRINT_FAILURES if (mErrorCode == MB_FAILURE) std::cerr << "ErrorInfo2 Failed:: " << mErrorMsg.str() << std::endl; #endif } }; class ErrorInfo3 { ErrorCode mErrorCode; std::string mErrorMsg; public: ErrorInfo3(ErrorCode err_code = MB_FAILURE, const char* err_msg = "") : mErrorCode(err_code), mErrorMsg(err_msg) { } ErrorInfo3(const ErrorInfo3& err_info) : mErrorCode(err_info.mErrorCode), mErrorMsg(err_info.mErrorMsg) { } ~ErrorInfo3() { #ifdef PRINT_FAILURES if (mErrorCode == MB_FAILURE) std::cerr << "ErrorInfo3 Failed:: " << mErrorMsg << std::endl; #endif } }; class ErrorInfo4 { ErrorCode mErrorCode; const char* mErrorMsg; public: ErrorInfo4(ErrorCode err_code = MB_FAILURE, const char* err_msg = "") : mErrorCode(err_code), mErrorMsg(err_msg) { } ErrorInfo4(const ErrorInfo4& err_info) : mErrorCode(err_info.mErrorCode), mErrorMsg(err_info.mErrorMsg) { } ~ErrorInfo4() { #ifdef PRINT_FAILURES if (mErrorCode == MB_FAILURE) std::cerr << "ErrorInfo4 Failed:: " << mErrorMsg << std::endl; #endif } }; class ErrorContext { ErrorCode mErrorCode; const char* mErrorMsg; public: ErrorContext(ErrorCode err_code = MB_FAILURE, const char* err_msg = "") : mErrorCode(err_code), mErrorMsg(err_msg) { } ~ErrorContext() { #ifdef PRINT_FAILURES if (mErrorCode == MB_FAILURE) { std::cerr << "ErrorInfo5 Failed:: Message -- " << mErrorMsg << std::endl; } #endif } }; typedef ErrorContext* ErrorInfo5; #define THROW_ERROR(errCode,errMsgStr) { \ std::stringstream _ostr; \ _ostr << errMsgStr; \ return new ErrorContext(errCode,_ostr.str().c_str()); \ } ErrorCode test_return_0(const long n) { return ( #ifdef RANDOMIZE_FAILURES dis(gen) < FAILURE_RATE ? #else false ? #endif MB_FAILURE : (n > 0 ? test_return_0(n-1) : MB_SUCCESS) ); } ErrorInfo1 test_return_1(const long n) { return ( #ifdef RANDOMIZE_FAILURES dis(gen) < FAILURE_RATE ? #else false ? #endif ErrorInfo1(MB_FAILURE) : (n > 0 ? test_return_1(n-1) : ErrorInfo1(MB_SUCCESS)) ); } ErrorInfo2 test_return_2(const long n) { return ( #ifdef RANDOMIZE_FAILURES dis(gen) < FAILURE_RATE ? #else false ? #endif ErrorInfo2(MB_FAILURE, "Returned message is MB_FAILURE") : (n > 0 ? test_return_2(n-1) : ErrorInfo2(MB_SUCCESS, "Returned message is MB_SUCCESS")) ); } ErrorInfo3 test_return_3(const long n) { return ( #ifdef RANDOMIZE_FAILURES dis(gen) < FAILURE_RATE ? #else false ? #endif ErrorInfo3(MB_FAILURE, "Returned message is MB_FAILURE") : (n > 0 ? test_return_3(n-1) : ErrorInfo3(MB_SUCCESS, "Returned message is MB_SUCCESS")) ); } ErrorInfo4 test_return_4(const long n) { return ( #ifdef RANDOMIZE_FAILURES dis(gen) < FAILURE_RATE ? #else false ? #endif ErrorInfo4(MB_FAILURE, "Returned message is MB_FAILURE") : (n > 0 ? test_return_4(n-1) : ErrorInfo4(MB_SUCCESS, "Returned message is MB_SUCCESS")) ); } ErrorInfo5 test_return_5(const long n) { #ifdef RANDOMIZE_FAILURES if (dis(gen) < FAILURE_RATE) { // new ErrorContext(MB_FAILURE, "Returned message is MB_FAILURE from Level = "+std::string(n)) THROW_ERROR(MB_FAILURE, "Returned message is MB_FAILURE from Level = " << n << " -- Thrown from ErrorContext") } else { return (n > 0 ? test_return_5(n-1) : NULL ); } #else return (n > 0 ? test_return_5(n-1) : NULL ); #endif } int test_case(int iterations, int nrecursions, int case_number, std::string case_str, double& duration) { #ifdef USE_CHRONO std::chrono::time_point start = std::chrono::system_clock::now(); #else std::clock_t start = std::clock(); #endif switch(case_number) { case 0: for (long i = 0; i < iterations; i++) #ifdef NO_RECURSION for (long j = 0; j < nrecursions; j++) ErrorCode err = test_return_0(1); // Change to use other test_return_x() version here for testing #else ErrorCode err = test_return_0(nrecursions); // Change to use other test_return_x() version here for testing #endif break; case 1: for (long i = 0; i < iterations; i++) #ifdef NO_RECURSION for (long j = 0; j < nrecursions; j++) ErrorInfo1 err = test_return_1(1); // Change to use other test_return_x() version here for testing #else ErrorInfo1 err = test_return_1(nrecursions); // Change to use other test_return_x() version here for testing #endif break; case 2: for (long i = 0; i < iterations; i++) #ifdef NO_RECURSION for (long j = 0; j < nrecursions; j++) ErrorInfo2 err = test_return_2(1); // Change to use other test_return_x() version here for testing #else ErrorInfo2 err = test_return_2(nrecursions); // Change to use other test_return_x() version here for testing #endif break; case 3: for (long i = 0; i < iterations; i++) #ifdef NO_RECURSION for (long j = 0; j < nrecursions; j++) ErrorInfo3 err = test_return_3(1); // Change to use other test_return_x() version here for testing #else ErrorInfo3 err = test_return_3(nrecursions); // Change to use other test_return_x() version here for testing #endif break; case 4: for (long i = 0; i < iterations; i++) #ifdef NO_RECURSION for (long j = 0; j < nrecursions; j++) ErrorInfo4 err = test_return_4(1); // Change to use other test_return_x() version here for testing #else ErrorInfo4 err = test_return_4(nrecursions); // Change to use other test_return_x() version here for testing #endif break; case 5: for (long i = 0; i < iterations; i++) { #ifdef NO_RECURSION for (long j = 0; j < nrecursions; j++) { ErrorInfo5 err = test_return_5(1); // Change to use other test_return_x() version here for testing if (err) { // can optionally print something here delete err; } } #else ErrorInfo5 err = test_return_5(nrecursions); // Change to use other test_return_x() version here for testing if (err) { // can optionally print something here delete err; } #endif } break; default: std::cerr << "Error. Unknown test method.\n"; exit(1); } #ifdef USE_CHRONO std::chrono::duration elapsed=std::chrono::system_clock::now()-start; duration = elapsed.count(); #else //duration = (double) ( std::clock() - start ) / CLOCKS_PER_SEC; duration = difftime (std::clock(),start); #endif //std::cout<<"Timing: " << case_str << " == " << duration <<'\n'; return 0; } int main(int argc, char** argv) { const long max_iterations=100000; const long max_recursions=1000; long iterations, nrecursions; std::cout << "Performance data table:: NITERATIONS XX NRECURSIONS \n"; std::cout << "NRECURSIONS\tPlain_ErrorCode\tObject_ErrorInfo\tStringStream_ErrorInfo\tstd::string_ErrorInfo\tconst_char*_ErrorInfo\tconst char* stacked ErrorInfo\n"; std::cout << std::scientific; int result=0; double duration_errcode, duration_errinfo, duration_sstrerrinfo, duration_strerrinfo, duration_charerrinfo, duration_stcharerrinfo; for (iterations=1; iterations <= max_iterations; iterations *= 10) { std::cout << "\nNITERATIONS == " << iterations << "\n"; for (nrecursions=1; nrecursions <= max_recursions; nrecursions *= 10) { //std::cout << "\n NITERATIONS == " << iterations << "\t NRECURSIONS == " << nrecursions << "\n"; std::cout << nrecursions << "\t" ;std::cout.flush(); result = test_case(iterations, nrecursions, 0, "Plain ErrorCode", duration_errcode); std::cout << duration_errcode << "\t" ;std::cout.flush(); result = test_case(iterations, nrecursions, 1, "Object ErrorInfo", duration_errinfo); std::cout << duration_errinfo << "\t" ;std::cout.flush(); result = test_case(iterations, nrecursions, 2, "StringStream ErrorInfo", duration_sstrerrinfo); std::cout << duration_sstrerrinfo << "\t" ;std::cout.flush(); result = test_case(iterations, nrecursions, 3, "std::string ErrorInfo", duration_strerrinfo); std::cout << duration_strerrinfo << "\t" ;std::cout.flush(); result = test_case(iterations, nrecursions, 4, "const char* ErrorInfo", duration_charerrinfo); std::cout << duration_charerrinfo << "\t" ;std::cout.flush(); result = test_case(iterations, nrecursions, 5, "const char* Stacked ErrorInfo", duration_stcharerrinfo); // Unfinished implementation - basically wanted to store data at every level std::cout << duration_stcharerrinfo << "\n";std::cout.flush(); } std::cout << "\n"; } return 0; }