diff --git a/host-configs/tpls.cmake b/host-configs/tpls.cmake index 1a4ab1701e6..ded9597c5be 100644 --- a/host-configs/tpls.cmake +++ b/host-configs/tpls.cmake @@ -109,3 +109,7 @@ endif() if(EXISTS ${GEOS_TPL_DIR}/mathpresso) set(MATHPRESSO_DIR ${GEOS_TPL_DIR}/mathpresso CACHE PATH "" FORCE) endif() + +if(EXISTS ${GEOS_TPL_DIR}/cpptrace) + set(CPPTRACE_DIR ${GEOS_TPL_DIR}/cpptrace CACHE PATH "" FORCE) +endif() \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 36dc61610ac..49f662b4c91 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,6 +133,10 @@ if( ENABLE_HIP ) list( APPEND extraComponentsLinkList blt::hip ) endif() +if( ENABLE_CPPTRACE ) + list( APPEND extraComponentsLinkList cpptrace::cpptrace ) +endif() + blt_add_executable( NAME geosx SOURCES main/main.cpp DEPENDS_ON geosx_core diff --git a/src/cmake/GeosxConfig.cmake b/src/cmake/GeosxConfig.cmake index 39c206418f8..c79c1e07a8b 100644 --- a/src/cmake/GeosxConfig.cmake +++ b/src/cmake/GeosxConfig.cmake @@ -1,5 +1,6 @@ set( PREPROCESSOR_DEFINES BOUNDS_CHECK CALIPER + CPPTRACE CHAI CUDA CUDA_NVTOOLSEXT diff --git a/src/cmake/thirdparty/SetupGeosxThirdParty.cmake b/src/cmake/thirdparty/SetupGeosxThirdParty.cmake index 2bb024b2b05..b400c51f3d8 100644 --- a/src/cmake/thirdparty/SetupGeosxThirdParty.cmake +++ b/src/cmake/thirdparty/SetupGeosxThirdParty.cmake @@ -897,6 +897,7 @@ else() set(ENABLE_PETSC OFF CACHE BOOL "" FORCE) message(STATUS "Not using PETSc") endif() + ################################ # VTK ################################ @@ -935,6 +936,41 @@ else() message(STATUS "Not using VTK") endif() +################################ +# CPPTRACE +################################ +if( DEFINED CPPTRACE_DIR ) + message( STATUS "CPPTRACE_DIR = ${CPPTRACE_DIR}" ) + + if( DEFINED ZSTD_DIR ) + message( STATUS "ZSTD_DIR = ${ZSTD_DIR}" ) + list( PREPEND CMAKE_PREFIX_PATH "${ZSTD_DIR}" ) + endif() + if( DEFINED LIBDWARF_DIR ) + message( STATUS "LIBDWARF_DIR = ${LIBDWARF_DIR}" ) + list( PREPEND CMAKE_PREFIX_PATH "${LIBDWARF_DIR}" ) + endif() + + find_package( cpptrace REQUIRED + PATHS ${CPPTRACE_DIR} + NO_DEFAULT_PATH ) + + if( DEFINED cpptrace_VERSION ) + message( " ----> cpptrace_VERSION=${cpptrace_VERSION}") + endif() + + blt_convert_to_system_includes( TARGET cpptrace::cpptrace ) + + set( ENABLE_CPPTRACE ON CACHE BOOL "" ) + set( thirdPartyLibs ${thirdPartyLibs} cpptrace::cpptrace ) +else() + if( ENABLE_CPPTRACE ) + message( WARNING "ENABLE_CPPTRACE is ON but CPPTRACE_DIR isn't defined." ) + endif() + + set( ENABLE_CPPTRACE OFF CACHE BOOL "" ) + message( STATUS "Not using cpptrace" ) +endif() ################################ # uncrustify diff --git a/src/coreComponents/common/CMakeLists.txt b/src/coreComponents/common/CMakeLists.txt index d0143b9564b..9dbfd6081f1 100644 --- a/src/coreComponents/common/CMakeLists.txt +++ b/src/coreComponents/common/CMakeLists.txt @@ -43,6 +43,7 @@ set( common_headers logger/Logger.hpp logger/ErrorHandling.hpp logger/ExternalErrorHandler.hpp + logger/StackTrace.hpp MpiWrapper.hpp Path.hpp Span.hpp @@ -82,6 +83,7 @@ set( common_sources logger/Logger.cpp logger/ErrorHandling.cpp logger/ExternalErrorHandler.cpp + logger/StackTrace.cpp BufferAllocator.cpp MemoryInfos.cpp MpiWrapper.cpp @@ -136,6 +138,10 @@ if( ENABLE_CALIPER ) endif() endif() +if( ENABLE_CPPTRACE ) + list( APPEND dependencyList cpptrace::cpptrace ) +endif() + blt_add_library( NAME common SOURCES ${common_sources} HEADERS ${common_headers} diff --git a/src/coreComponents/common/GeosxConfig.hpp.in b/src/coreComponents/common/GeosxConfig.hpp.in index 0c8ee16237f..aec6965c34b 100644 --- a/src/coreComponents/common/GeosxConfig.hpp.in +++ b/src/coreComponents/common/GeosxConfig.hpp.in @@ -38,6 +38,9 @@ /// Enables use of CHAI (CMake option ENABLE_CHAI) #cmakedefine GEOS_USE_CHAI +/// Enables use of Cpptrace (CMake option ENABLE_CPPTRACE) +#cmakedefine GEOS_USE_CPPTRACE + /// Enables use of Mathpresso library (CMake option ENABLE_MATHPRESSO) #cmakedefine GEOS_USE_MATHPRESSO diff --git a/src/coreComponents/common/initializeEnvironment.cpp b/src/coreComponents/common/initializeEnvironment.cpp index e43263c8528..89d071ef26c 100644 --- a/src/coreComponents/common/initializeEnvironment.cpp +++ b/src/coreComponents/common/initializeEnvironment.cpp @@ -22,6 +22,7 @@ #include "logger/ErrorHandling.hpp" #include "logger/ExternalErrorHandler.hpp" #include +#include "logger/StackTrace.hpp" // TPL includes #include #include @@ -86,7 +87,7 @@ void setupLogger() } else { - std::string const stackHistory = LvArray::system::stackTrace( true ); + std::string const stackHistory = StackTrace::stackTrace(); DiagnosticMsg diagnosticMsg; ErrorLogger::global().flushErrorMsg( DiagnosticMsgBuilder::init( diagnosticMsg, MsgType::Error, errorMsg, @@ -109,7 +110,7 @@ void setupLogger() ExternalErrorHandler::instance().flush( "before signal error output" ); // error message output - std::string const stackHistory = LvArray::system::stackTrace( true ); + std::string const stackHistory = StackTrace::signalSafeStackTrace(); DiagnosticMsg diagnosticMsg; ErrorLogger::global().flushErrorMsg( DiagnosticMsgBuilder::init( diagnosticMsg, MsgType::ExternalError, "", diff --git a/src/coreComponents/common/logger/ErrorHandling.cpp b/src/coreComponents/common/logger/ErrorHandling.cpp index 6881e11259a..a21a7348bb4 100644 --- a/src/coreComponents/common/logger/ErrorHandling.cpp +++ b/src/coreComponents/common/logger/ErrorHandling.cpp @@ -18,8 +18,11 @@ */ #include "ErrorHandling.hpp" +#include "Logger.hpp" +#include "StackTrace.hpp" #include "common/DataTypes.hpp" #include "common/logger/Logger.hpp" +#include "common/logger/StackTrace.hpp" #include "common/format/StringUtilities.hpp" #include @@ -66,7 +69,7 @@ DiagnosticMsgBuilder ErrorLogger::initCurrentExceptionMessage( MsgType msgType, m_getCurrentExceptionMsg = DiagnosticMsgBuilder::init( diagnosticMsg, msgType, msgContent, rank ) - .addCallStackInfo( LvArray::system::stackTrace( true ) ) + .addCallStackInfo( StackTrace::stackTrace() ) .getDiagnosticMsg(); return DiagnosticMsgBuilder::modify( m_getCurrentExceptionMsg ); } @@ -203,20 +206,24 @@ DiagnosticMsgBuilder & DiagnosticMsgBuilder::addRank( integer const rank ) DiagnosticMsgBuilder & DiagnosticMsgBuilder::addCallStackInfo( std::string_view ossStackTrace ) { + m_errorMsg.m_sourceCallStack.clear(); + m_errorMsg.m_isValidStackTrace = false; + std::string str = std::string( ossStackTrace ); std::istringstream iss( str ); std::string stackLine; - std::size_t index; - std::regex pattern( R"(Frame \d+: \S+)" ); + std::regex lvArrayPattern( R"(Frame \d+:\s*)" ); + std::regex cpptracePattern( R"(^\s*#\d+\s+)" ); while( std::getline( iss, stackLine ) ) { - if( std::regex_search( stackLine, pattern )) + std::smatch m; + if( std::regex_search( stackLine, m, lvArrayPattern ) || + std::regex_search( stackLine, m, cpptracePattern ) ) { m_errorMsg.m_isValidStackTrace = true; - index = stackLine.find( ':' ); - m_errorMsg.m_sourceCallStack.push_back( stackLine.substr( index + 1 ) ); + m_errorMsg.m_sourceCallStack.push_back( m.suffix().str() ); } } diff --git a/src/coreComponents/common/logger/Logger.hpp b/src/coreComponents/common/logger/Logger.hpp index b23ba87a39d..f692ff96b3a 100644 --- a/src/coreComponents/common/logger/Logger.hpp +++ b/src/coreComponents/common/logger/Logger.hpp @@ -23,6 +23,7 @@ // Source includes #include "LvArray/src/Macros.hpp" #include "common/logger/GeosExceptions.hpp" +#include "common/logger/StackTrace.hpp" // System includes #include @@ -161,7 +162,7 @@ ::geos::logger::internal::g_rank ) \ .setCodeLocation( __FILE__, __LINE__ ) \ .setCause( __causemsgsoss.str() ) \ - .addCallStackInfo( LvArray::system::stackTrace( true ) ) \ + .addCallStackInfo( StackTrace::stackTrace() ) \ .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ )); \ GEOS_GLOBAL_LOGGER.flushCurrentExceptionMessage(); \ LvArray::system::callErrorHandler(); \ @@ -248,7 +249,7 @@ ::geos::logger::internal::g_rank ) \ .setCodeLocation( __FILE__, __LINE__ ) \ .setCause( __causemsgsoss.str() ) \ - .addCallStackInfo( LvArray::system::stackTrace( true ) ) \ + .addCallStackInfo( StackTrace::stackTrace() ) \ .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ )) \ .getDiagnosticMsg(); \ auto ex = GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ )(); \ @@ -341,7 +342,7 @@ ::geos::logger::internal::g_rank ) \ .setCodeLocation( __FILE__, __LINE__ ) \ .setCause( __causemsgsoss.str() ) \ - .addCallStackInfo( LvArray::system::stackTrace( true ) ) \ + .addCallStackInfo( StackTrace::stackTrace() ) \ .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ )) \ .getDiagnosticMsg() ); \ } \ diff --git a/src/coreComponents/common/logger/StackTrace.cpp b/src/coreComponents/common/logger/StackTrace.cpp new file mode 100644 index 00000000000..1fa59d0be60 --- /dev/null +++ b/src/coreComponents/common/logger/StackTrace.cpp @@ -0,0 +1,91 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StackTrace.cpp + */ + +#include "StackTrace.hpp" +#include "LvArray/src/system.hpp" + +#include "common/GeosxConfig.hpp" +#ifdef GEOS_USE_CPPTRACE +#include +#include +#include +#endif + +namespace geos +{ + + +std::string StackTrace::stackTrace() +{ +#ifdef GEOS_USE_CPPTRACE + return formatter().format( cpptrace::generate_trace( /* skip = */ 1 ) ); +#else + return LvArray::system::stackTrace( true ); +#endif +} + +std::string StackTrace::signalSafeStackTrace() +{ + return LvArray::system::stackTrace( true ); +} + +#ifdef GEOS_USE_CPPTRACE +cpptrace::formatter const & StackTrace::formatter() +{ + static cpptrace::formatter const fmt = cpptrace::formatter{} + .header( "" ) + .addresses( cpptrace::formatter::address_mode::none ) + .paths( cpptrace::formatter::path_mode::basename ) + .symbols( cpptrace::formatter::symbol_mode::pretty ) + .snippets( false ) + .columns( true ) + .filtered_frame_placeholders( false ) + .filter( []( cpptrace::stacktrace_frame const & frame ) + { + static char const * const blacklist[] = { + "__cxa_throw", + "__cxa_rethrow", + "_Unwind_RaiseException", + "_Unwind_Resume", + "cpptrace::detail::", + "cpptrace::v1::detail::", + "cpptrace::try_catch::", + "cpptrace::v1::try_catch::", + }; + for( char const * symbolToHide : blacklist ) + { + if( frame.symbol.find( symbolToHide ) != std::string::npos ) + { + return false; + } + } + return true; + } ); + + return fmt; +} + +std::string StackTrace::formatStackTrace( cpptrace::stacktrace const & stacktrace ) +{ + return formatter().format( stacktrace ); +} +#endif + + +} /* namespace geos */ diff --git a/src/coreComponents/common/logger/StackTrace.hpp b/src/coreComponents/common/logger/StackTrace.hpp new file mode 100644 index 00000000000..04d04978431 --- /dev/null +++ b/src/coreComponents/common/logger/StackTrace.hpp @@ -0,0 +1,75 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StackTrace.hpp + */ + +#ifndef GEOS_COMMON_LOGGER_STACKTRACE_HPP +#define GEOS_COMMON_LOGGER_STACKTRACE_HPP + +#include "common/GeosxConfig.hpp" // For the following guards +#ifdef GEOS_USE_CPPTRACE +#include +#include +#endif + +#include + +namespace geos +{ + +/** + * @brief Utility class to interact with stack traces. + */ +class StackTrace +{ +public: + + /** + * @brief Get a stack trace for the current thread. + * @return The stack trace as a string. + * @note Not signal-safe. Use signalSafeStackTrace() from inside a signal handler. + */ + static std::string stackTrace(); + + /** + * @brief Get a stack trace from a context where signal-safety is required. + * @return The stack trace as a string. + * @note Implementation reverts back to LvArray::system stack trace for signal-safety + */ + static std::string signalSafeStackTrace(); + +#ifdef GEOS_USE_CPPTRACE + /** + * @brief Access the configured cpptrace formatter. + * @return The formatter instance. + */ + static cpptrace::formatter const & formatter(); + + /** + * @brief Format a cpptrace stacktrace using the configured formatter. + * @param stacktrace The cpptrace stack trace to format. + * @return Formatted stack trace string. + */ + static std::string formatStackTrace( cpptrace::stacktrace const & stacktrace ); +#endif + +}; + + +} /* namespace geos */ + +#endif /* GEOS_COMMON_LOGGER_STACKTRACE_HPP */ diff --git a/src/docs/sphinx/buildGuide/BuildProcess.rst b/src/docs/sphinx/buildGuide/BuildProcess.rst index cd3910c451c..88d5a4e914c 100644 --- a/src/docs/sphinx/buildGuide/BuildProcess.rst +++ b/src/docs/sphinx/buildGuide/BuildProcess.rst @@ -70,6 +70,7 @@ Option Default Explanation ``ENABLE_CUDA_NVTOOLSEXT`` ``OFF`` Enable CUDA NVTX user instrumentation (via GEOS_MARK_SCOPE or GEOS_MARK_FUNCTION macros) ``ENABLE_HIP`` ``OFF`` Build with HIP/ROCM (also applies to TPLs) ``ENABLE_DOCS`` ``ON`` Build documentation (Sphinx and Doxygen) +``ENABLE_CPPTRACE`` ``OFF`` Enable cpptrace stack traces ``ENABLE_WARNINGS_AS_ERRORS`` ``ON`` Treat all warnings as errors ``ENABLE_PVTPackage`` ``ON`` Enable PVTPackage library (required for compositional flow runs) ``ENABLE_TOTALVIEW_OUTPUT`` ``OFF`` Enables TotalView debugger custom view of GEOS data structures diff --git a/src/docs/sphinx/buildGuide/Dependencies.rst b/src/docs/sphinx/buildGuide/Dependencies.rst index 03824bb29a4..a8f26eceda4 100644 --- a/src/docs/sphinx/buildGuide/Dependencies.rst +++ b/src/docs/sphinx/buildGuide/Dependencies.rst @@ -25,6 +25,7 @@ Adiak_ 0.2.0 :code:`ENABLE_CALIPER` :code:`ADIAK_DIR` Caliper_ 2.4.0 :code:`ENABLE_CALIPER` :code:`CALIPER_DIR` Instrumentation and performance profiling library. conduit_ 0.5.0 *mandatory* :code:`CONDUIT_DIR` Simplified Data Exchange for HPC Simulations. CHAI_ 2.2.2 *mandatory* :code:`CHAI_DIR` Copy-hiding array abstraction to automatically migrate data between memory spaces. +cpptrace_ 1.0.0 :code:`ENABLE_CPPTRACE` :code:`CPPTRACE_DIR` Optional stack trace library that captures full throw-site stack traces (including STL frames). RAJA_ 0.12.1 *mandatory* :code:`RAJA_DIR` Collection of C++ software abstractions that enable architecture portability for HPC applications. hdf5_ 1.10.5 *mandatory* :code:`HDF5_DIR` High-performance data management and storage suite. mathpresso_ 2015-12-15 :code:`ENABLE_MATHPRESSO` :code:`MATHPRESSO_DIR` Mathematical Expression Parser and JIT Compiler. @@ -56,6 +57,7 @@ uncrustify_ 401a409 :code:`ENABLE_UNCRUSTIFY` :code:`UNCRUSTIFY_EXECUTABL .. _Caliper: https://github.com/LLNL/Caliper .. _conduit: https://github.com/LLNL/conduit .. _CHAI : https://github.com/LLNL/CHAI +.. _cpptrace : https://github.com/jeremy-rifkin/cpptrace .. _RAJA : https://github.com/LLNL/RAJA .. _hdf5 : https://portal.hdfgroup.org/display/HDF5/HDF5 .. _mathpresso : https://github.com/kobalicek/mathpresso diff --git a/src/main/main.cpp b/src/main/main.cpp index 00c7a560ef6..1d9ad3657ba 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -16,6 +16,8 @@ // Source includes #include "common/logger/ErrorHandling.hpp" #include "common/logger/Logger.hpp" +#include "common/logger/StackTrace.hpp" +#include "common/GeosxConfig.hpp" #include "common/MemoryInfos.hpp" #include "common/TimingMacros.hpp" #include "common/Units.hpp" @@ -23,6 +25,9 @@ #include "mainInterface/ProblemManager.hpp" #include "mainInterface/GeosxState.hpp" #include "mainInterface/version.hpp" +#ifdef GEOS_USE_CPPTRACE +#include +#endif using namespace geos; @@ -30,7 +35,7 @@ using namespace geos; int main( int argc, char *argv[] ) { - try + auto runMain = [&] { std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now(); @@ -68,30 +73,66 @@ int main( int argc, char *argv[] ) GEOS_LOG_RANK_0( GEOS_FMT( "total time {}", units::TimeFormatInfo::fromDuration( totalTime ) ) ); GEOS_LOG_RANK_0( GEOS_FMT( "initialization time {}", units::TimeFormatInfo::fromDuration( initTime ) ) ); GEOS_LOG_RANK_0( GEOS_FMT( "run time {}", units::TimeFormatInfo::fromDuration( runTime ) ) ); + }; - return 0; - } // A NotAnError is thrown if "-h" or "--help" option is used. - catch( NotAnError const & ) + auto onNotAnError = [&]( NotAnError const & ) { basicCleanup( false ); - return 0; - } - catch( geos::Exception & e ) + }; + + auto onGeosException = [&]( geos::Exception & ) { // GEOS generated exceptions management +#ifdef GEOS_USE_CPPTRACE + std::string const stacktrace = StackTrace::formatStackTrace( cpptrace::from_current_exception() ); +#else + std::string const stacktrace = LvArray::system::stackTrace( true ); +#endif + if( !stacktrace.empty() ) + { + ErrorLogger::global().modifyCurrentExceptionMessage().addCallStackInfo( stacktrace ); + } ErrorLogger::global().flushCurrentExceptionMessage(); basicCleanup( true ); LvArray::system::callErrorHandler(); - } - catch( std::exception const & e ) + }; + + auto onStdException = [&]( std::exception const & e ) { // native exceptions management +#ifdef GEOS_USE_CPPTRACE + std::string const stacktrace = StackTrace::formatStackTrace( cpptrace::from_current_exception() ); +#else + std::string const stacktrace = LvArray::system::stackTrace( true ); +#endif ErrorLogger::global().flushErrorMsg( ErrorLogger::global().initCurrentExceptionMessage( MsgType::Exception, e.what(), ::geos::logger::internal::g_rank ) - .addCallStackInfo( LvArray::system::stackTrace( true ) ) + .addCallStackInfo( stacktrace ) .getDiagnosticMsg()); basicCleanup( true ); LvArray::system::callErrorHandler(); + }; + +#ifdef GEOS_USE_CPPTRACE + cpptrace::try_catch( runMain, onNotAnError, onGeosException, onStdException ); +#else + try + { + runMain(); + } + catch( NotAnError const & ) + { + onNotAnError(); } + catch( geos::Exception & ) + { + onGeosException(); + } + catch( std::exception const & e ) + { + onStdException( e ); + } +#endif + return 0; }