#include "common/Utilities.h" #include #include #include #include #include #include #ifdef USE_MPI #include "mpi.h" #endif // Detect the OS and include system dependent headers #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) || defined(_MSC_VER) // Note: windows has not been testeds #define USE_WINDOWS #include #include #include #include #include #include #define mkdir(path, mode) _mkdir(path) //#pragma comment(lib, psapi.lib) //added //#pragma comment(linker, /DEFAULTLIB:psapi.lib) #elif defined(__APPLE__) #define USE_MAC #include #include #include #include #include #elif defined(__linux) || defined(__unix) || defined(__posix) #define USE_LINUX #include #include #include #include #else #error Unknown OS #endif #ifdef __GNUC__ #define USE_ABI #include #endif /**************************************************************************** * Function to terminate the program * ****************************************************************************/ static bool abort_printMemory = true; static bool abort_printStack = true; static bool abort_throwException = false; static int force_exit = 0; void Utilities::setAbortBehavior( bool printMemory, bool printStack, bool throwException ) { abort_printMemory = printMemory; abort_printStack = printStack; abort_throwException = throwException; } void Utilities::abort(const std::string &message, const std::string &filename, const int line) { std::stringstream msg; msg << "Program abort called in file `" << filename << "' at line " << line << std::endl; // Add the memory usage and call stack to the error message if ( abort_printMemory ) { size_t N_bytes = Utilities::getMemoryUsage(); msg << "Bytes used = " << N_bytes << std::endl; } if ( abort_printStack ) { std::vector stack = Utilities::getCallStack(); msg << std::endl; msg << "Stack Trace:\n"; for (size_t i=0; i1 ) { exit(-1); } else if ( !abort_throwException ) { // Use MPI_abort (will terminate all processes) force_exit = 2; std::cerr << msg.str(); #if defined(USE_MPI) || defined(HAVE_MPI) int initialized=0, finalized=0; MPI_Initialized(&initialized); MPI_Finalized(&finalized); if ( initialized!=0 && finalized==0 ) MPI_Abort(MPI_COMM_WORLD,-1); #endif exit(-1); } else if ( force_exit>0 ) { exit(-1); } else { // Throw and standard exception (allows the use of try, catch) throw std::logic_error(msg.str()); } } /**************************************************************************** * Function to handle MPI errors * ****************************************************************************/ /*#if defined(USE_MPI) || defined(HAVE_MPI) MPI_Errhandler mpierr; void MPI_error_handler_fun( MPI_Comm *comm, int *err, ... ) { if ( *err==MPI_ERR_COMM && *comm==MPI_COMM_WORLD ) { // Special error handling for an invalid MPI_COMM_WORLD std::cerr << "Error invalid MPI_COMM_WORLD"; exit(-1); } int msg_len=0; char message[1000]; MPI_Error_string( *err, message, &msg_len ); if ( msg_len <= 0 ) abort("Unkown error in MPI"); abort( "Error calling MPI routine:\n" + std::string(message) ); } #endif*/ /**************************************************************************** * Function to handle unhandled exceptions * ****************************************************************************/ void term_func_abort(int err) { printf("Exiting due to abort (%i)\n",err); std::vector stack = Utilities::getCallStack(); std::string message = "Stack Trace:\n"; for (size_t i=0; i( new MPI_Errhandler ); MPI_Comm_create_errhandler( MPI_error_handler_fun, mpierr.get() ); } MPI_Comm_set_errhandler( mpi.getCommunicator(), *mpierr ); MPI_Comm_set_errhandler( MPI_COMM_WORLD, *mpierr ); #endif } void Utilities::clearMPIErrorHandler( ) { #if defined(USE_MPI) || defined(HAVE_MPI) if ( mpierr.get()!=NULL ) MPI_Errhandler_free( mpierr.get() ); // Delete the error handler mpierr.reset(); MPI_Comm_set_errhandler( MPI_COMM_SELF, MPI_ERRORS_ARE_FATAL ); MPI_Comm_set_errhandler( MPI_COMM_WORLD, MPI_ERRORS_ARE_FATAL ); #endif }*/ /**************************************************************************** * Function to get the memory usage * * Note: this function should be thread-safe * ****************************************************************************/ #if defined(USE_MAC) // Get the page size on mac static size_t page_size = static_cast(sysconf(_SC_PAGESIZE)); #endif static size_t N_bytes_initialization = Utilities::getMemoryUsage(); size_t Utilities::getMemoryUsage() { size_t N_bytes = 0; #if defined(USE_LINUX) struct mallinfo meminfo = mallinfo(); size_t size_hblkhd = static_cast( meminfo.hblkhd ); size_t size_uordblks = static_cast( meminfo.uordblks ); N_bytes = static_cast( size_hblkhd + size_uordblks ); #elif defined(USE_MAC) struct task_basic_info t_info; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) { return 0; } N_bytes = t_info.virtual_size; #elif defined(USE_WINDOWS) PROCESS_MEMORY_COUNTERS memCounter; GetProcessMemoryInfo( GetCurrentProcess(), &memCounter, sizeof(memCounter) ); N_bytes = memCounter.WorkingSetSize; #endif return N_bytes; } /**************************************************************************** * Function to get the current call stack * ****************************************************************************/ std::vector Utilities::getCallStack() { std::vector stack_list; #if defined(USE_ABI) void *trace[100]; memset(trace,0,100*sizeof(void*)); Dl_info dlinfo; int status; const char *symname; char *demangled=NULL; int trace_size = backtrace(trace,100); for (int i=0; i( lInfoMemory.AllocationBase ); ::TCHAR lNameModule[ 1024 ]; ::HMODULE hBaseAllocation = reinterpret_cast< ::HMODULE >( lBaseAllocation ); ::GetModuleFileName( hBaseAllocation, lNameModule, 1024 ); PIMAGE_DOS_HEADER lHeaderDOS = reinterpret_cast( lBaseAllocation ); if ( lHeaderDOS==NULL ) continue; PIMAGE_NT_HEADERS lHeaderNT = reinterpret_cast( lBaseAllocation + lHeaderDOS->e_lfanew ); PIMAGE_SECTION_HEADER lHeaderSection = IMAGE_FIRST_SECTION( lHeaderNT ); ::DWORD64 lRVA = lFrameStack.AddrPC.Offset - lBaseAllocation; ::DWORD64 lNumberSection = ::DWORD64(); ::DWORD64 lOffsetSection = ::DWORD64(); for( int lCnt = ::DWORD64(); lCnt < lHeaderNT->FileHeader.NumberOfSections; lCnt++, lHeaderSection++ ) { ::DWORD64 lSectionBase = lHeaderSection->VirtualAddress; ::DWORD64 lSectionEnd = lSectionBase + max( lHeaderSection->SizeOfRawData, lHeaderSection->Misc.VirtualSize ); if( ( lRVA >= lSectionBase ) && ( lRVA <= lSectionEnd ) ) { lNumberSection = lCnt + 1; lOffsetSection = lRVA - lSectionBase; break; } } std::stringstream stream; stream << lNameModule << " : 000" << lNumberSection << " : " << reinterpret_cast(lOffsetSection); stack_list.push_back(stream.str()); } #else #warning Stack trace is not supported on this compiler/OS #endif return stack_list; } // Functions to get the time and timer resolution #if defined(USE_WINDOWS) double Utilities::time() { LARGE_INTEGER end, f; QueryPerformanceFrequency(&f); QueryPerformanceCounter(&end); double time = ((double)end.QuadPart)/((double)f.QuadPart); return time; } double Utilities::tick() { LARGE_INTEGER f; QueryPerformanceFrequency(&f); double resolution = ((double)1.0)/((double)f.QuadPart); return resolution; } #elif defined(USE_LINUX) || defined(USE_MAC) double Utilities::time() { timeval current_time; gettimeofday(¤t_time,NULL); double time = ((double)current_time.tv_sec)+1e-6*((double)current_time.tv_usec); return time; } double Utilities::tick() { timeval start, end; gettimeofday(&start,NULL); gettimeofday(&end,NULL); while ( end.tv_sec==start.tv_sec && end.tv_usec==start.tv_usec ) gettimeofday(&end,NULL); double resolution = ((double)(end.tv_sec-start.tv_sec))+1e-6*((double)(end.tv_usec-start.tv_usec)); return resolution; } #else #error Unknown OS #endif