Commit eacaeaf6 authored by Tomáš Oberhuber's avatar Tomáš Oberhuber
Browse files

Merge branch 'develop' of geraldine.fjfi.cvut.cz:/local/projects/tnl/tnl into develop

parents ab92eec3 e1eed23d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
ADD_SUBDIRECTORY( Config )
ADD_SUBDIRECTORY( Containers )
ADD_SUBDIRECTORY( Debugging )
ADD_SUBDIRECTORY( Devices )
ADD_SUBDIRECTORY( Experimental )
ADD_SUBDIRECTORY( Functions )
+7 −0
Original line number Diff line number Diff line
SET( headers
         FPE.h
         MemoryUsage.h
         StackBacktrace.h
)
   
INSTALL( FILES ${headers} DESTINATION include/tnl-${tnlVersion}/TNL/Debugging )
+69 −0
Original line number Diff line number Diff line
/***************************************************************************
                          MeshConfigBase.h  -  description
                             -------------------
    begin                : Nov 6, 2016
    copyright            : (C) 2016 by Tomas Oberhuber et al.
    email                : tomas.oberhuber@fjfi.cvut.cz
 ***************************************************************************/

/* See Copyright Notice in tnl/Copyright */

#pragma once

#include <cfenv>
#include <signal.h>

#include <TNL/Debugging/StackBacktrace.h>

namespace TNL {
namespace Debugging {

static void
printStackBacktraceAndAbort( int sig = 0 )
{
   if( sig == SIGSEGV )
      fprintf(stderr, "Invalid memory reference, printing backtrace and aborting...\n");
   else if( sig == SIGFPE ) {
      /*
       * Unfortunately it is not possible to get the floating-point exception type
       * from a signal handler. Otherwise, it would be done this way:
       *
       *    fprintf(stderr, "Floating-point exception");
       *    if(fetestexcept(FE_DIVBYZERO))  fprintf(stderr, " FE_DIVBYZERO");
       *    if(fetestexcept(FE_INEXACT))    fprintf(stderr, " FE_INEXACT");
       *    if(fetestexcept(FE_INVALID))    fprintf(stderr, " FE_INVALID");
       *    if(fetestexcept(FE_OVERFLOW))   fprintf(stderr, " FE_OVERFLOW");
       *    if(fetestexcept(FE_UNDERFLOW))  fprintf(stderr, " FE_UNDERFLOW");
       *    fprintf(stderr, " occurred, printing backtrace and aborting...\n");
       */
      fprintf(stderr, "Floating-point exception occurred, printing backtrace and aborting...\n");
   }
   else
      fprintf( stderr, "Aborting due to signal %d...\n", sig );
   printStackBacktrace();
   abort();
}

/*
 * Registers handler for SIGSEGV and SIGFPE signals and enables conversion of
 * floating-point exceptions into SIGFPE. This is useful e.g. for tracing where
 * NANs occurred. Example usage:
 *
 * int main()
 * {
 *    #ifndef NDEBUG
 *       registerFloatingPointExceptionTracking()
 *    #endif
 *    [start some computation here...]
 * }
 */
static void
trackFloatingPointExceptions()
{
   signal( SIGSEGV, printStackBacktraceAndAbort );
   signal( SIGFPE,  printStackBacktraceAndAbort );
   feenableexcept( FE_ALL_EXCEPT & ~FE_INEXACT );
}

} // namespace Debugging
} // namespace TNL
+70 −0
Original line number Diff line number Diff line
/***************************************************************************
                          MeshConfigBase.h  -  description
                             -------------------
    begin                : Nov 6, 2016
    copyright            : (C) 2016 by Tomas Oberhuber et al.
    email                : tomas.oberhuber@fjfi.cvut.cz
 ***************************************************************************/

/* See Copyright Notice in tnl/Copyright */

#pragma once

#include <iostream>
#include <fstream>
#include <string>
#include <limits>

namespace TNL {
namespace Debugging {

/*
 * Prints memory usage of the current process into the specified stream.
 *
 * The information is obtained from /proc/self/status, which is assumed to be
 * present on the system. The meaning of the printed values is following:
 *  
 *  - VmSize: Virtual memory size.
 *  - VmRSS: Resident set size.
 *  - VmHWM: Peak resident set size ("high water mark").
 *
 * See the proc(5) manual on Linux for details.
 */
static void
printMemoryUsage( std::ostream& str = std::cerr )
{
   std::ifstream meminfo("/proc/self/status");
   if( meminfo.fail() ) {
      std::cerr << "error: unable to open /proc/self/status" << std::endl;
      return;
   }

   unsigned vm = 0;
   unsigned rss = 0;
   unsigned hwm = 0;

   std::string desc;
   while( meminfo.good() ) {
       // extract description (first column)
       meminfo >> desc;

       if( desc == "VmSize:" )
           meminfo >> vm;
       if( desc == "VmHWM:" )
           meminfo >> hwm;
       if( desc == "VmRSS:" )
           meminfo >> rss;

       // ignore the rest of irrelevant lines
       meminfo.ignore( std::numeric_limits< std::streamsize >::max(), '\n' );
   }

   str << "Memory usage (MiB): "
       << "VmSize = " << vm / 1024 << "MiB, "
       << "VmRSS = " << rss / 1024 << "MiB, "
       << "VmHWM = " << hwm / 1024 << "MiB, "
       << std::endl;
}

} // namespace Debugging
} // namespace TNL
+104 −0
Original line number Diff line number Diff line
/***************************************************************************
                          MeshConfigBase.h  -  description
                             -------------------
    begin                : Nov 6, 2016
    copyright            : (C) 2016 by Tomas Oberhuber et al.
    email                : tomas.oberhuber@fjfi.cvut.cz
 ***************************************************************************/

/* See Copyright Notice in tnl/Copyright */

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>

namespace TNL {
namespace Debugging {

/*
 * Print a demangled stack backtrace of the caller function to FILE* out.
 *
 * Reference: http://panthema.net/2008/0901-stacktrace-demangled/
 *
 * Note that the program must be linked with the -rdynamic flag, otherwise
 * demangling will not work.
 */
static void
printStackBacktrace( FILE *out = stderr, unsigned int max_frames = 63 )
{
   fprintf(out, "stack trace:\n");

   // storage array for stack trace address data
   void* addrlist[max_frames+1];

   // retrieve current stack addresses
   int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));

   if (addrlen == 0) {
      fprintf(out, "  <empty, possibly corrupt>\n");
      return;
   }

   // resolve addresses into strings containing "filename(function+address)",
   // this array must be free()-ed
   char** symbollist = backtrace_symbols(addrlist, addrlen);

   // allocate string which will be filled with the demangled function name
   size_t funcnamesize = 256;
   char* funcname = (char*)malloc(funcnamesize);

   // iterate over the returned symbol lines. skip the first, it is the
   // address of this function.
   for (int i = 1; i < addrlen; i++) {
      char *begin_name = 0, *begin_offset = 0, *end_offset = 0;

      // find parentheses and +address offset surrounding the mangled name:
      // ./module(function+0x15c) [0x8048a6d]
      for (char *p = symbollist[i]; *p; ++p) {
         if (*p == '(')
            begin_name = p;
         else if (*p == '+')
            begin_offset = p;
         else if (*p == ')' && begin_offset) {
            end_offset = p;
            break;
         }
      }

      if (begin_name && begin_offset && end_offset && begin_name < begin_offset) {
         *begin_name++ = '\0';
         *begin_offset++ = '\0';
         *end_offset = '\0';

         // mangled name is now in [begin_name, begin_offset) and caller
         // offset in [begin_offset, end_offset). now apply
         // __cxa_demangle():

         int status;
         char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
         if (status == 0) {
            funcname = ret; // use possibly realloc()-ed string
            fprintf(out, "  %d %s : %s+%s\n",
               i, symbollist[i], funcname, begin_offset);
         }
         else {
            // demangling failed. Output function name as a C function with no arguments.
            fprintf(out, "  %d %s : %s()+%s\n",
               i, symbollist[i], begin_name, begin_offset);
         }
      }
      else {
         // couldn't parse the line? print the whole line.
         fprintf(out, "  %d %s\n", i, symbollist[i]);
      }
   }

   free(funcname);
   free(symbollist);
}

} // namespace Debugging
} // namespace TNL