combined updates
This commit is contained in:
commit
23e221d84e
50 files changed
+5065
-4667
No files matched your search
@@ -0,0 +1,42 @@
|
||||
#ifndef included_StackTraceErrorHandlers
|
||||
#define included_StackTraceErrorHandlers
|
||||
|
||||
|
||||
#include "StackTrace/StackTrace.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "mpi.h"
|
||||
|
||||
|
||||
namespace StackTrace
|
||||
{
|
||||
|
||||
|
||||
/*!
|
||||
* Set the error handler
|
||||
* @param[in] abort Function to terminate the program: abort(msg,type)
|
||||
*/
|
||||
void setErrorHandler( std::function<void( const StackTrace::abort_error& )> abort );
|
||||
|
||||
//! Clear the error handler
|
||||
void clearErrorHandler();
|
||||
|
||||
|
||||
//! Set an error handler for MPI
|
||||
void setMPIErrorHandler( MPI_Comm comm );
|
||||
|
||||
//! Clear an error handler for MPI
|
||||
void clearMPIErrorHandler( MPI_Comm comm );
|
||||
|
||||
|
||||
//! Initialize globalCallStack functionallity
|
||||
void globalCallStackInitialize( MPI_Comm comm );
|
||||
|
||||
//! Clean up globalCallStack functionallity
|
||||
void globalCallStackFinalize();
|
||||
|
||||
|
||||
} // namespace StackTrace
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
This directory contains code external code released with permission under the license of this project.
|
||||
|
||||
Original code and license are availible at:
|
||||
https://bitbucket.org/mberrill/StackTrace
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_StackTrace
|
||||
#define included_StackTrace
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "StackTrace/string_view.h"
|
||||
|
||||
|
||||
namespace StackTrace {
|
||||
|
||||
//! Class to contain stack trace info for a single thread/process
|
||||
struct stack_info {
|
||||
uint32_t line;
|
||||
void *address;
|
||||
void *address2;
|
||||
std::array<char, 56> object;
|
||||
std::array<char, 48> objectPath;
|
||||
std::array<char, 64> filename;
|
||||
std::array<char, 64> filenamePath;
|
||||
std::array<char, 256> function;
|
||||
//! Default constructor
|
||||
stack_info();
|
||||
//! Reset the stack
|
||||
void clear();
|
||||
//! Operator==
|
||||
bool operator==( const stack_info &rhs ) const;
|
||||
//! Operator!=
|
||||
bool operator!=( const stack_info &rhs ) const;
|
||||
//! Get the minimum width to print the addresses
|
||||
int getAddressWidth() const;
|
||||
//! Print the stack info
|
||||
std::string print( int widthAddress = 16, int widthObject = 20, int widthFunction = 32 ) const;
|
||||
//! Print the stack info
|
||||
static void print( std::ostream &out, const std::vector<stack_info> &stack,
|
||||
const StackTrace::string_view &prefix = "" );
|
||||
//! Print the stack info
|
||||
void print2(
|
||||
char *txt, int widthAddress = 16, int widthObject = 20, int widthFunction = 32 ) const;
|
||||
//! Compute the number of bytes needed to store the object
|
||||
size_t size() const;
|
||||
//! Pack the data to a byte array, returning a pointer to the end of the data
|
||||
char *pack( char *ptr ) const;
|
||||
//! Unpack the data from a byte array, returning a pointer to the end of the data
|
||||
const char *unpack( const char *ptr );
|
||||
};
|
||||
|
||||
|
||||
//! Class to contain stack trace info for multiple threads/processes
|
||||
struct multi_stack_info {
|
||||
int N; // Number of threads/processes
|
||||
stack_info stack; // Current stack item
|
||||
std::vector<multi_stack_info> children; // Children
|
||||
//! Default constructor
|
||||
multi_stack_info() : N( 0 ) {}
|
||||
//! Construct from a simple call stack
|
||||
explicit multi_stack_info( const std::vector<stack_info> & );
|
||||
//! Copy constructor from a simple call stack
|
||||
multi_stack_info &operator=( const std::vector<stack_info> & );
|
||||
//! Reset the stack
|
||||
void clear();
|
||||
//! Is the stack empty
|
||||
bool empty() const { return N == 0; }
|
||||
//! Add the given stack to the multistack
|
||||
void add( size_t len, const stack_info *stack );
|
||||
//! Add the given stack to the multistack
|
||||
void add( const multi_stack_info &stack );
|
||||
//! Compute the number of bytes needed to store the object
|
||||
size_t size() const;
|
||||
//! Pack the data to a byte array, returning a pointer to the end of the data
|
||||
char *pack( char *ptr ) const;
|
||||
//! Unpack the data from a byte array, returning a pointer to the end of the data
|
||||
const char *unpack( const char *ptr );
|
||||
//! Print the stack info
|
||||
std::vector<std::string> print( const StackTrace::string_view &prefix = "" ) const;
|
||||
//! Print the stack info
|
||||
void print( std::ostream &out, const StackTrace::string_view &prefix = "" ) const;
|
||||
//! Print the stack info
|
||||
std::string printString( const StackTrace::string_view &prefix = "" ) const;
|
||||
|
||||
private:
|
||||
template<class FUN>
|
||||
void print2( int Np, char *prefix, int w[3], bool c, FUN &fun ) const;
|
||||
int getAddressWidth() const;
|
||||
int getObjectWidth() const;
|
||||
int getFunctionWidth() const;
|
||||
};
|
||||
|
||||
|
||||
//!< Terminate type
|
||||
enum class terminateType : uint8_t { signal, exception, abort, MPI, unknown };
|
||||
enum class printStackType : uint8_t { local = 1, threaded = 2, global = 3 };
|
||||
|
||||
//!< Class to contain exception info from abort
|
||||
class abort_error : public std::exception
|
||||
{
|
||||
public:
|
||||
std::string message; //!< Abort message
|
||||
std::string filename; //!< File where abort was called
|
||||
terminateType type; //!< What caused the termination
|
||||
printStackType stackType; //!< Print the local stack, all threads, or global call stack
|
||||
uint8_t signal; //!< Signal number
|
||||
int line; //!< Line number where abort was called
|
||||
size_t bytes; //!< Memory in use during abort
|
||||
std::vector<void *> stack; //!< Local call stack for abort
|
||||
public:
|
||||
virtual const char *what() const noexcept override;
|
||||
abort_error();
|
||||
virtual ~abort_error() {}
|
||||
|
||||
private:
|
||||
mutable std::string d_msg;
|
||||
};
|
||||
|
||||
|
||||
//!< Class to contain symbol information
|
||||
struct symbols_struct {
|
||||
char type;
|
||||
void *address;
|
||||
std::array<char, 56> obj;
|
||||
std::array<char, 56> objPath;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Get the current call stack
|
||||
* @details This function returns the current call stack for the current thread
|
||||
* @return Returns vector containing the stack
|
||||
*/
|
||||
std::vector<stack_info> getCallStack();
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Get the current call stack for a thread
|
||||
* @details This function returns the current call stack for the given thread
|
||||
* @param[in] id The thread id of the stack we want to return
|
||||
* @return Returns vector containing the stack
|
||||
*/
|
||||
std::vector<stack_info> getCallStack( std::thread::native_handle_type id );
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Get the current call stack for all threads
|
||||
* @details This function returns the current call stack for all threads
|
||||
* in the current process.
|
||||
* Note: This functionality may not be availible on all platforms
|
||||
* @return Returns vector containing the stack
|
||||
*/
|
||||
multi_stack_info getAllCallStacks();
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Get the current call stack for all threads/processes
|
||||
* @details This function returns the current call stack for all threads
|
||||
* for all processes in the current process. This function requires
|
||||
* the user to call globalCallStackInitialize() before calling this
|
||||
* routine, and globalCallStackFinalize() before exiting.
|
||||
* Note: This functionality may not be availible on all platforms
|
||||
* @return Returns vector containing the stack
|
||||
*/
|
||||
multi_stack_info getGlobalCallStacks();
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Clean up the stack trace
|
||||
* @details This function modifies the stack trace to remove entries
|
||||
* related to acquiring the stack trace in an attempt to make it
|
||||
* more useful for display/users.
|
||||
* @param[in,out] stack The stack trace to modify
|
||||
*/
|
||||
void cleanupStackTrace( multi_stack_info &stack );
|
||||
|
||||
|
||||
//! Function to return the current call stack for the current thread
|
||||
std::vector<void *> backtrace();
|
||||
|
||||
//! Function to return the current call stack for the given thread
|
||||
std::vector<void *> backtrace( std::thread::native_handle_type id );
|
||||
|
||||
//! Function to return the current call stack for all threads
|
||||
std::vector<std::vector<void *>> backtraceAll();
|
||||
|
||||
|
||||
//! Function to return the stack info for a given address
|
||||
stack_info getStackInfo( void *address );
|
||||
|
||||
|
||||
//! Function to return the stack info for a given address
|
||||
std::vector<stack_info> getStackInfo( const std::vector<void *> &address );
|
||||
|
||||
|
||||
//! Function to return the signal name
|
||||
const char *signalName( int signal );
|
||||
|
||||
|
||||
/*!
|
||||
* Return the symbols from the current executable (not availible for all platforms)
|
||||
* @return Returns the symbols loaded
|
||||
*/
|
||||
std::vector<symbols_struct> getSymbols();
|
||||
|
||||
|
||||
//! Clear internal symbol data
|
||||
void clearSymbols();
|
||||
|
||||
|
||||
/*!
|
||||
* Return the name of the executable
|
||||
* @return Returns the name of the executable (usually the full path)
|
||||
*/
|
||||
std::string getExecutable();
|
||||
|
||||
|
||||
/*!
|
||||
* Return the search path for the symbols
|
||||
* @return Returns the search path for the symbols
|
||||
*/
|
||||
std::string getSymPaths();
|
||||
|
||||
|
||||
/*!
|
||||
* Set the given signals to the handler
|
||||
* @param[in] signals Signals to handle
|
||||
* @param[in] handler Function to terminate the program: abort(signal)
|
||||
*/
|
||||
void setSignals( const std::vector<int> &signals, void ( *handler )( int ) );
|
||||
|
||||
|
||||
//! Clear a signal set by setSignals
|
||||
void clearSignal( int signal );
|
||||
|
||||
|
||||
//! Clear a signal set by setSignals
|
||||
void clearSignals( const std::vector<int> &signals );
|
||||
|
||||
|
||||
//! Clear all signals set by setSignals
|
||||
void clearSignals();
|
||||
|
||||
|
||||
//! Raise a signal
|
||||
void raiseSignal( int signal );
|
||||
|
||||
|
||||
//! Return a list of all signals that can be caught
|
||||
std::vector<int> allSignalsToCatch();
|
||||
|
||||
//! Return a default list of signals to catch
|
||||
std::vector<int> defaultSignalsToCatch();
|
||||
|
||||
|
||||
//! Get a list of the active threads
|
||||
std::vector<std::thread::native_handle_type> activeThreads();
|
||||
|
||||
//! Get a handle to this thread
|
||||
std::thread::native_handle_type thisThread();
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Call system command
|
||||
* @details This function calls a system command, waits for the program
|
||||
* to execute, captures and returns the output and exit code.
|
||||
* @param[in] cmd Command to execute
|
||||
* @param[out] exit_code Exit code returned from child process
|
||||
* @return Returns string containing the output
|
||||
*/
|
||||
std::string exec( const string_view &cmd, int &exit_code );
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Create stack from string
|
||||
* @details This function creates the call stack from the string generated by print
|
||||
* @param[in] str Vector of strings containing call stack
|
||||
* @return Returns the call stack
|
||||
*/
|
||||
multi_stack_info generateFromString( const std::vector<std::string> &str );
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Create stack from string
|
||||
* @details This function creates the call stack from the string
|
||||
* @param[in] str String containing call stack
|
||||
* @return Returns the call stack
|
||||
*/
|
||||
multi_stack_info generateFromString( const std::string &str );
|
||||
|
||||
|
||||
} // namespace StackTrace
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,296 @@
|
||||
#define NOMINMAX
|
||||
#include "StackTrace/Utilities.h"
|
||||
#include "StackTrace/ErrorHandlers.h"
|
||||
#include "StackTrace/StackTrace.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef USE_MPI
|
||||
#include "mpi.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_TIMER
|
||||
#include "MemoryApp.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define perr std::cerr
|
||||
|
||||
|
||||
// Detect the OS
|
||||
// clang-format off
|
||||
#if defined( WIN32 ) || defined( _WIN32 ) || defined( WIN64 ) || defined( _WIN64 ) || defined( _MSC_VER )
|
||||
#define USE_WINDOWS
|
||||
#elif defined( __APPLE__ )
|
||||
#define USE_MAC
|
||||
#elif defined( __linux ) || defined( __linux__ ) || defined( __unix ) || defined( __posix )
|
||||
#define USE_LINUX
|
||||
#define USE_NM
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
// Include system dependent headers
|
||||
// clang-format off
|
||||
#ifdef USE_WINDOWS
|
||||
#include <process.h>
|
||||
#include <psapi.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <execinfo.h>
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <ctime>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef USE_LINUX
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#ifdef USE_MAC
|
||||
#include <mach/mach.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
namespace StackTrace {
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to find an entry *
|
||||
****************************************************************************/
|
||||
template<class TYPE>
|
||||
inline size_t findfirst( const std::vector<TYPE> &X, TYPE Y )
|
||||
{
|
||||
if ( X.empty() )
|
||||
return 0;
|
||||
size_t lower = 0;
|
||||
size_t upper = X.size() - 1;
|
||||
if ( X[lower] >= Y )
|
||||
return lower;
|
||||
if ( X[upper] < Y )
|
||||
return upper;
|
||||
while ( ( upper - lower ) != 1 ) {
|
||||
size_t value = ( upper + lower ) / 2;
|
||||
if ( X[value] >= Y )
|
||||
upper = value;
|
||||
else
|
||||
lower = value;
|
||||
}
|
||||
return upper;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to terminate the program *
|
||||
****************************************************************************/
|
||||
static bool abort_throwException = false;
|
||||
static printStackType abort_stackType = printStackType::global;
|
||||
static int force_exit = 0;
|
||||
void Utilities::setAbortBehavior( bool throwException, int stackType )
|
||||
{
|
||||
abort_throwException = throwException;
|
||||
abort_stackType = static_cast<printStackType>( stackType );
|
||||
}
|
||||
void Utilities::abort( const std::string &message, const std::string &filename, const int line )
|
||||
{
|
||||
abort_error err;
|
||||
err.message = message;
|
||||
err.filename = filename;
|
||||
err.type = terminateType::abort;
|
||||
err.line = line;
|
||||
err.bytes = Utilities::getMemoryUsage();
|
||||
err.stackType = abort_stackType;
|
||||
err.stack = StackTrace::backtrace();
|
||||
throw err;
|
||||
}
|
||||
static void terminate( const StackTrace::abort_error &err )
|
||||
{
|
||||
clearErrorHandler();
|
||||
// Print the message and abort
|
||||
if ( force_exit > 1 ) {
|
||||
std::abort();
|
||||
} else if ( !abort_throwException ) {
|
||||
// Use MPI_abort (will terminate all processes)
|
||||
force_exit = 2;
|
||||
perr << err.what();
|
||||
#if defined( USE_MPI ) || defined( HAVE_MPI )
|
||||
int initialized = 0, finalized = 0;
|
||||
MPI_Initialized( &initialized );
|
||||
MPI_Finalized( &finalized );
|
||||
if ( initialized != 0 && finalized == 0 ) {
|
||||
clearMPIErrorHandler( MPI_COMM_WORLD );
|
||||
MPI_Abort( MPI_COMM_WORLD, -1 );
|
||||
}
|
||||
#endif
|
||||
std::abort();
|
||||
} else {
|
||||
perr << err.what();
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Functions to set the error handler *
|
||||
****************************************************************************/
|
||||
static void setTerminateErrorHandler()
|
||||
{
|
||||
// Set the terminate routine for runtime errors
|
||||
StackTrace::setErrorHandler( terminate );
|
||||
}
|
||||
void Utilities::setErrorHandlers()
|
||||
{
|
||||
#ifdef USE_MPI
|
||||
setMPIErrorHandler( MPI_COMM_WORLD );
|
||||
setMPIErrorHandler( MPI_COMM_SELF );
|
||||
#endif
|
||||
setTerminateErrorHandler();
|
||||
}
|
||||
void Utilities::clearErrorHandlers()
|
||||
{
|
||||
#ifdef USE_MPI
|
||||
clearMPIErrorHandler( MPI_COMM_WORLD );
|
||||
clearMPIErrorHandler( MPI_COMM_SELF );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to get the memory usage *
|
||||
* Note: this function should be thread-safe *
|
||||
****************************************************************************/
|
||||
// clang-format off
|
||||
#if defined( USE_MAC ) || defined( USE_LINUX )
|
||||
// Get the page size on mac or linux
|
||||
static size_t page_size = static_cast<size_t>( sysconf( _SC_PAGESIZE ) );
|
||||
#endif
|
||||
size_t Utilities::getSystemMemory()
|
||||
{
|
||||
#if defined( USE_LINUX )
|
||||
static long pages = sysconf( _SC_PHYS_PAGES );
|
||||
size_t N_bytes = pages * page_size;
|
||||
#elif defined( USE_MAC )
|
||||
int mib[2] = { CTL_HW, HW_MEMSIZE };
|
||||
u_int namelen = sizeof( mib ) / sizeof( mib[0] );
|
||||
uint64_t size;
|
||||
size_t len = sizeof( size );
|
||||
size_t N_bytes = 0;
|
||||
if ( sysctl( mib, namelen, &size, &len, nullptr, 0 ) == 0 )
|
||||
N_bytes = size;
|
||||
#elif defined( USE_WINDOWS )
|
||||
MEMORYSTATUSEX status;
|
||||
status.dwLength = sizeof( status );
|
||||
GlobalMemoryStatusEx( &status );
|
||||
size_t N_bytes = status.ullTotalPhys;
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
return N_bytes;
|
||||
}
|
||||
size_t Utilities::getMemoryUsage()
|
||||
{
|
||||
#ifdef USE_TIMER
|
||||
size_t N_bytes = MemoryApp::getTotalMemoryUsage();
|
||||
#else
|
||||
#if defined( USE_LINUX )
|
||||
struct mallinfo meminfo = mallinfo();
|
||||
size_t size_hblkhd = static_cast<unsigned int>( meminfo.hblkhd );
|
||||
size_t size_uordblks = static_cast<unsigned int>( meminfo.uordblks );
|
||||
size_t N_bytes = 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;
|
||||
}
|
||||
size_t N_bytes = t_info.virtual_size;
|
||||
#elif defined( USE_WINDOWS )
|
||||
PROCESS_MEMORY_COUNTERS memCounter;
|
||||
GetProcessMemoryInfo( GetCurrentProcess(), &memCounter, sizeof( memCounter ) );
|
||||
size_t N_bytes = memCounter.WorkingSetSize;
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
#endif
|
||||
return N_bytes;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* 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, nullptr );
|
||||
double time = ( (double) current_time.tv_sec ) + 1e-6 * ( (double) current_time.tv_usec );
|
||||
return time;
|
||||
}
|
||||
double Utilities::tick()
|
||||
{
|
||||
timeval start, end;
|
||||
gettimeofday( &start, nullptr );
|
||||
gettimeofday( &end, nullptr );
|
||||
while ( end.tv_sec == start.tv_sec && end.tv_usec == start.tv_usec )
|
||||
gettimeofday( &end, nullptr );
|
||||
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
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Cause a segfault *
|
||||
****************************************************************************/
|
||||
void Utilities::cause_segfault()
|
||||
{
|
||||
int *ptr = nullptr;
|
||||
ptr[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Call system command *
|
||||
****************************************************************************/
|
||||
std::string Utilities::exec( const string_view &cmd, int &exit_code )
|
||||
{
|
||||
return StackTrace::exec( cmd, exit_code );
|
||||
}
|
||||
|
||||
|
||||
} // namespace StackTrace
|
||||
@@ -0,0 +1,99 @@
|
||||
#ifndef included_StackTrace_Utilities
|
||||
#define included_StackTrace_Utilities
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "StackTrace/StackTrace.h"
|
||||
#include "StackTrace/string_view.h"
|
||||
|
||||
|
||||
namespace StackTrace {
|
||||
namespace Utilities {
|
||||
|
||||
|
||||
/*!
|
||||
* Aborts the run after printing an error message with file and
|
||||
* line number information.
|
||||
*/
|
||||
void abort( const std::string &message, const std::string &filename, const int line );
|
||||
|
||||
|
||||
/*!
|
||||
* Set the behavior of abort
|
||||
* @param throwException Throw an exception instead of MPI_Abort (default is false)
|
||||
* @param stackType Type of stack to get (1: thread local stack, 2: all threads, 3: global)
|
||||
*/
|
||||
void setAbortBehavior( bool throwException, int stackType = 2 );
|
||||
|
||||
|
||||
//! Function to set the error handlers
|
||||
void setErrorHandlers();
|
||||
|
||||
//! Function to clear the error handlers
|
||||
void clearErrorHandlers();
|
||||
|
||||
|
||||
/*!
|
||||
* Function to get the memory availible.
|
||||
* This function will return the total memory availible
|
||||
* Note: depending on the implimentation, this number may be rounded to
|
||||
* to a multiple of the page size.
|
||||
* If this function fails, it will return 0.
|
||||
*/
|
||||
size_t getSystemMemory();
|
||||
|
||||
|
||||
/*!
|
||||
* Function to get the memory usage.
|
||||
* This function will return the total memory used by the application.
|
||||
* Note: depending on the implimentation, this number may be rounded to
|
||||
* to a multiple of the page size.
|
||||
* If this function fails, it will return 0.
|
||||
*/
|
||||
size_t getMemoryUsage();
|
||||
|
||||
|
||||
//! Function to get an arbitrary point in time
|
||||
double time();
|
||||
|
||||
|
||||
//! Function to get the resolution of time
|
||||
double tick();
|
||||
|
||||
|
||||
/*!
|
||||
* Sleep for X ms
|
||||
* @param N Time to sleep (ms)
|
||||
*/
|
||||
inline void sleep_ms( int N ) { std::this_thread::sleep_for( std::chrono::milliseconds( N ) ); }
|
||||
|
||||
|
||||
/*!
|
||||
* Sleep for X s
|
||||
* @param N Time to sleep (s)
|
||||
*/
|
||||
inline void sleep_s( int N ) { std::this_thread::sleep_for( std::chrono::seconds( N ) ); }
|
||||
|
||||
|
||||
//! Cause a segfault
|
||||
void cause_segfault();
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Call system command
|
||||
* @details This function calls a system command, waits for the program
|
||||
* to execute, captures and returns the output and exit code.
|
||||
* @param[in] cmd Command to execute
|
||||
* @param[out] exit_code Exit code returned from child process
|
||||
* @return Returns string containing the output
|
||||
*/
|
||||
std::string exec( const StackTrace::string_view &cmd, int &exit_code );
|
||||
|
||||
|
||||
} // namespace Utilities
|
||||
} // namespace StackTrace
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
#ifndef included_StackTrace_stringView
|
||||
#define included_StackTrace_stringView
|
||||
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
|
||||
namespace StackTrace {
|
||||
|
||||
// string_view
|
||||
class string_view
|
||||
{
|
||||
public:
|
||||
// Constants:
|
||||
static constexpr size_t npos = size_t( -1 );
|
||||
|
||||
// Constructions
|
||||
constexpr string_view() noexcept : d_data( nullptr ), d_size( 0 ) {}
|
||||
constexpr string_view( string_view&& ) noexcept = default;
|
||||
constexpr string_view( const string_view& ) noexcept = default;
|
||||
constexpr string_view( const char* s ) : d_data( s ), d_size( s ? strlen( s ) : 0 ) {}
|
||||
constexpr string_view( const char* s, size_t count ) : d_data( s ), d_size( count ) {}
|
||||
inline string_view( const std::string& s ) : d_data( s.data() ), d_size( s.size() ) {}
|
||||
|
||||
// Assignment
|
||||
constexpr string_view& operator=( string_view&& other ) noexcept = default;
|
||||
constexpr string_view& operator=( const string_view& other ) noexcept = default;
|
||||
|
||||
// Iterators
|
||||
constexpr const char* begin() const noexcept { return d_data; }
|
||||
constexpr const char* end() const noexcept { return d_data + d_size; }
|
||||
constexpr const char* cbegin() const noexcept { return begin(); }
|
||||
constexpr const char* cend() const noexcept { return end(); }
|
||||
|
||||
// capacity
|
||||
constexpr size_t size() const noexcept { return d_size; }
|
||||
constexpr size_t length() const noexcept { return d_size; }
|
||||
constexpr bool empty() const noexcept { return d_size == 0; }
|
||||
|
||||
// Element access
|
||||
constexpr const char& operator[]( size_t pos ) const
|
||||
{
|
||||
if ( pos >= d_size )
|
||||
throw std::out_of_range( "string_view[]" );
|
||||
return d_data[pos];
|
||||
}
|
||||
constexpr const char& at( size_t pos ) const
|
||||
{
|
||||
if ( pos >= d_size )
|
||||
throw std::out_of_range( "string_view::at()" );
|
||||
return d_data[pos];
|
||||
}
|
||||
constexpr const char& front() const
|
||||
{
|
||||
if ( d_size == 0 )
|
||||
throw std::out_of_range( "front()" );
|
||||
return d_data[0];
|
||||
}
|
||||
constexpr const char& back() const
|
||||
{
|
||||
if ( d_size == 0 )
|
||||
throw std::out_of_range( "back()" );
|
||||
return d_data[size() - 1];
|
||||
}
|
||||
constexpr const char* data() const noexcept { return d_data; }
|
||||
|
||||
// Swap data
|
||||
void swap( string_view& other ) noexcept
|
||||
{
|
||||
std::swap( d_data, other.d_data );
|
||||
std::swap( d_size, other.d_size );
|
||||
}
|
||||
|
||||
// String operations
|
||||
size_t copy( char* dest, size_t n, size_t pos = 0 ) const
|
||||
{
|
||||
if ( pos > size() )
|
||||
throw std::out_of_range( "string_view::copy()" );
|
||||
const size_t rlen = std::min( n, size() - pos );
|
||||
memcpy( dest, data() + pos, rlen );
|
||||
return rlen;
|
||||
}
|
||||
constexpr string_view substr( size_t pos = 0, size_t n = npos ) const
|
||||
{
|
||||
if ( pos > size() )
|
||||
throw std::out_of_range( "string_view::substr()" );
|
||||
return string_view( data() + pos, std::min( n, size() - pos ) );
|
||||
}
|
||||
|
||||
// Find
|
||||
constexpr size_t find( char ch, size_t pos = 0 ) const noexcept
|
||||
{
|
||||
for ( size_t i = pos; i < d_size; i++ )
|
||||
if ( d_data[i] == ch )
|
||||
return i;
|
||||
return std::string::npos;
|
||||
}
|
||||
constexpr size_t find( string_view v, size_t pos = 0 ) const noexcept
|
||||
{
|
||||
size_t i = pos;
|
||||
size_t N = v.size();
|
||||
if ( N == 0 || N > ( d_size - pos ) )
|
||||
return std::string::npos;
|
||||
while ( i < ( d_size - N + 1 ) ) {
|
||||
size_t j = 0;
|
||||
for ( j = 0; j < N && i + j < d_size; j++ )
|
||||
if ( d_data[i + j] != v[j] )
|
||||
break;
|
||||
if ( j == N )
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
// compare()
|
||||
constexpr int compare( const string_view& other ) const noexcept
|
||||
{
|
||||
int N = std::min( size(), other.size() );
|
||||
int result = 0;
|
||||
for ( int i = 0; i < N && result == 0; i++ )
|
||||
if ( d_data[i] != other[i] )
|
||||
result = d_data[i] < other[i] ? -i : i;
|
||||
if ( result == 0 )
|
||||
result = size() == other.size() ? 0 : size() < other.size() ? -1 : 1;
|
||||
return result;
|
||||
}
|
||||
constexpr int compare( size_t pos1, size_t n1, string_view other ) const
|
||||
{
|
||||
return substr( pos1, n1 ).compare( other );
|
||||
}
|
||||
constexpr int compare( size_t pos1, size_t n1, string_view other, size_t pos2, size_t n2 ) const
|
||||
{
|
||||
return substr( pos1, n1 ).compare( other.substr( pos2, n2 ) );
|
||||
}
|
||||
constexpr int compare( char const* s ) const { return compare( string_view( s ) ); }
|
||||
constexpr int compare( size_t pos1, size_t n1, char const* s ) const
|
||||
{
|
||||
return substr( pos1, n1 ).compare( string_view( s ) );
|
||||
}
|
||||
constexpr int compare( size_t pos1, size_t n1, char const* s, size_t n2 ) const
|
||||
{
|
||||
return substr( pos1, n1 ).compare( string_view( s, n2 ) );
|
||||
}
|
||||
|
||||
explicit operator std::string() const { return std::string( begin(), end() ); }
|
||||
std::string to_string() const { return std::string( begin(), end() ); }
|
||||
|
||||
private:
|
||||
const char* d_data;
|
||||
size_t d_size;
|
||||
};
|
||||
|
||||
|
||||
// Non-member functions:
|
||||
constexpr inline bool operator==( const string_view& lhs, const string_view& rhs ) noexcept
|
||||
{
|
||||
return lhs.compare( rhs ) == 0;
|
||||
}
|
||||
constexpr inline bool operator!=( const string_view& lhs, const string_view& rhs ) noexcept
|
||||
{
|
||||
return lhs.compare( rhs ) != 0;
|
||||
}
|
||||
constexpr inline bool operator<( const string_view& lhs, const string_view& rhs ) noexcept
|
||||
{
|
||||
return lhs.compare( rhs ) < 0;
|
||||
}
|
||||
|
||||
constexpr inline bool operator<=( const string_view& lhs, const string_view& rhs ) noexcept
|
||||
{
|
||||
return lhs.compare( rhs ) <= 0;
|
||||
}
|
||||
constexpr inline bool operator>( const string_view& lhs, const string_view& rhs ) noexcept
|
||||
{
|
||||
return lhs.compare( rhs ) > 0;
|
||||
}
|
||||
constexpr inline bool operator>=( const string_view& lhs, const string_view& rhs ) noexcept
|
||||
{
|
||||
return lhs.compare( rhs ) >= 0;
|
||||
}
|
||||
inline std::string to_string( const string_view& v ) { return std::string( v.begin(), v.end() ); }
|
||||
inline string_view to_string_view( std::string const& s )
|
||||
{
|
||||
return string_view( s.data(), s.size() );
|
||||
}
|
||||
inline std::ostream& operator<<( std::ostream& out, const string_view& s )
|
||||
{
|
||||
out << s.data();
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace StackTrace
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user