/// /// \author Peter Azmanov /// /// \copyright Copyright 2016, 2017, 2018 John Farrier /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// #include #include #include #ifdef WIN32 #include #endif // WIN32 #include #include // // Macros and general logics below taken from Google Test code, // see gtest/internal/gtest-port.h // gtest/src/gtest.cc // #ifndef CELERO_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. #ifndef _HAS_EXCEPTIONS #define _HAS_EXCEPTIONS 1 #endif // _HAS_EXCEPTIONS #define CELERO_HAS_EXCEPTIONS _HAS_EXCEPTIONS #elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. #define CELERO_HAS_EXCEPTIONS 1 #elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. #define CELERO_HAS_EXCEPTIONS 1 #elif defined(__IBMCPP__) && __EXCEPTIONS // xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. #define CELERO_HAS_EXCEPTIONS 1 #elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to // be turned of by +noeh compiler option if desired. #define CELERO_HAS_EXCEPTIONS 1 #else // For other compilers, we assume exceptions are disabled to be // conservative. #define CELERO_HAS_EXCEPTIONS 0 #endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // CELERO_HAS_EXCEPTIONS // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. #ifndef CELERO_HAS_SEH // The user didn't tell us, so we need to figure it out. #if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. #define CELERO_HAS_SEH 1 #else // Assume no SEH. #define CELERO_HAS_SEH 0 #endif #endif // CELERO_HAS_SEH namespace celero { bool ExceptionSettings::GetCatchExceptions() { return ExceptionSettings::instance().catchExceptions; } void ExceptionSettings::SetCatchExceptions(bool x) { ExceptionSettings::instance().catchExceptions = x; } ExceptionSettings& ExceptionSettings::instance() { static ExceptionSettings settings; return settings; } #if CELERO_HAS_SEH int HandleSEH(DWORD exceptionCode) { // see https://support.microsoft.com/en-us/kb/185294 const DWORD cppExceptionCode = 0xe06d7363; if((exceptionCode == EXCEPTION_BREAKPOINT) || (exceptionCode == cppExceptionCode)) { return EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; } const char* ExceptionCodeToStr(DWORD exceptionCode) { switch(exceptionCode) { case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION"; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT"; case EXCEPTION_DATATYPE_MISALIGNMENT: return "EXCEPTION_DATATYPE_MISALIGNMENT"; case EXCEPTION_FLT_DENORMAL_OPERAND: return "EXCEPTION_FLT_DENORMAL_OPERAND"; case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; case EXCEPTION_FLT_INEXACT_RESULT: return "EXCEPTION_FLT_INEXACT_RESULT"; case EXCEPTION_FLT_INVALID_OPERATION: return "EXCEPTION_FLT_INVALID_OPERATION"; case EXCEPTION_FLT_OVERFLOW: return "EXCEPTION_FLT_OVERFLOW"; case EXCEPTION_FLT_STACK_CHECK: return "EXCEPTION_FLT_STACK_CHECK"; case EXCEPTION_FLT_UNDERFLOW: return "EXCEPTION_FLT_UNDERFLOW"; case EXCEPTION_GUARD_PAGE: return "EXCEPTION_GUARD_PAGE"; case EXCEPTION_ILLEGAL_INSTRUCTION: return "EXCEPTION_ILLEGAL_INSTRUCTION"; case EXCEPTION_IN_PAGE_ERROR: return "EXCEPTION_IN_PAGE_ERROR"; case EXCEPTION_INT_DIVIDE_BY_ZERO: return "EXCEPTION_INT_DIVIDE_BY_ZERO"; case EXCEPTION_INT_OVERFLOW: return "EXCEPTION_INT_OVERFLOW"; case EXCEPTION_INVALID_DISPOSITION: return "EXCEPTION_INVALID_DISPOSITION"; case EXCEPTION_INVALID_HANDLE: return "EXCEPTION_INVALID_HANDLE"; case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; case EXCEPTION_PRIV_INSTRUCTION: return "EXCEPTION_PRIV_INSTRUCTION"; case EXCEPTION_SINGLE_STEP: return "EXCEPTION_SINGLE_STEP"; case EXCEPTION_STACK_OVERFLOW: return "EXCEPTION_STACK_OVERFLOW"; case STATUS_UNWIND_CONSOLIDATE: return "STATUS_UNWIND_CONSOLIDATE"; default: return "Unknown exception code."; } } #endif // CELERO_HAS_SEH std::pair RunAndCatchSEHExc(TestFixture& test, uint64_t threads, uint64_t calls, const celero::TestFixture::ExperimentValue& experimentValue) { #if CELERO_HAS_SEH __try { return std::make_pair(true, test.run(threads, calls, experimentValue)); } __except(HandleSEH(GetExceptionCode())) { const auto exceptionCode = GetExceptionCode(); celero::console::SetConsoleColor(celero::console::ConsoleColor::Red); std::cout << "SEH exception " << ExceptionCodeToStr(exceptionCode) << std::endl; celero::console::SetConsoleColor(celero::console::ConsoleColor::Default); return std::make_pair(false, 0); } #else // CELERO_HAS_SEH return std::make_pair(true, test.run(threads, calls, experimentValue)); #endif // CELERO_HAS_SEH } std::pair RunAndCatchExc(TestFixture& test, uint64_t threads, uint64_t calls, const celero::TestFixture::ExperimentValue& experimentValue) { if(ExceptionSettings::GetCatchExceptions() == true) { #if CELERO_HAS_EXCEPTIONS try { return RunAndCatchSEHExc(test, threads, calls, experimentValue); } catch(const std::exception& e) { celero::console::SetConsoleColor(celero::console::ConsoleColor::Red); std::cout << "C++ exception \"" << e.what() << "\"" << std::endl; celero::console::SetConsoleColor(celero::console::ConsoleColor::Default); } catch(...) { celero::console::SetConsoleColor(celero::console::ConsoleColor::Red); std::cout << "Unknown C++ exception" << std::endl; celero::console::SetConsoleColor(celero::console::ConsoleColor::Default); } return std::make_pair(false, 0); #else // CELERO_HAS_EXCEPTIONS return RunAndCatchSEHExc(test, threads, calls, experimentValue); #endif // CELERO_HAS_EXCEPTIONS } else { return std::make_pair(true, test.run(threads, calls, experimentValue)); } } } // namespace celero