Ignore:
Timestamp:
Jun 10, 2010, 3:10:19 PM (15 years ago)
Author:
Tillmann Crueger <crueger@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
Children:
6cfa36
Parents:
112b09
Message:

Made the memory-tracker output the function from which it was called.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Helpers/MemDebug.cpp

    r112b09 r6d6b54  
    1010#include <cstring>
    1111#include <boost/thread.hpp>
     12
     13#ifdef __GNUC__
     14#include <execinfo.h>
     15#include <cxxabi.h>
     16#endif
    1217
    1318using namespace std;
     
    3439      char file[length+1];
    3540      int line;
     41#ifdef __GNUC__  // function tracking only works with GCC
     42      // function names can get looooong
     43      enum {length2 = 256};
     44      char function[length2+1];
     45#endif
    3646      size_t nbytes;
    3747      bool isUsed;
     
    96106    for(entry_t *pos=begin;pos;pos=pos->next){
    97107      cout << "\nChunk of " << pos->info.nbytes << " bytes" << " still available" << endl;
     108#ifdef __GNUC__
     109      cout << "Chunk reserved at: " << pos->info.function
     110           << " (" << pos->info.file << ":" << pos->info.line  << ")" << endl;
     111#else
    98112      cout << "Chunk reserved at: " << pos->info.file << ":" << pos->info.line << endl;
     113#endif
    99114    }
    100115  }
     
    130145    deleteEntry(entry);
    131146  }
    132 }
     147
     148#ifdef __GNUC__
     149  // this function let's us find the caller's name
     150  char* getCaller(){
     151    // stack looks like this:
     152    // getCaller();
     153    // operator new();
     154    // function_we_are_looking_for(); <-
     155    const size_t max_depth = 3;
     156    void* stack_addrs[max_depth];
     157    size_t stack_depth;
     158    char **stack_strings=0;
     159    const char *func_name=0;
     160    const char *toplevel = "Global scope";
     161    char *retval=0;
     162
     163    // get the backtrace, depth three
     164    stack_depth   = backtrace(stack_addrs,max_depth);
     165    stack_strings = backtrace_symbols(stack_addrs, stack_depth);
     166    // used later for demangling
     167    // reserved here, so we can free it unconditionally
     168    char *dm_function = static_cast<char*>(malloc(entry_t::info_t::length2));
     169    if(!dm_function){
     170      // malloc failed... we are out of luck
     171      throw std::bad_alloc();
     172    }
     173
     174    // see if we found our function name
     175    if(stack_depth==max_depth){
     176      // find the mangled function name
     177      char *begin = stack_strings[max_depth-1];
     178      // function name starts with a (
     179      while(*begin && *begin!='(') ++begin;
     180      char *end=begin;
     181      while(*end && *end!='+') ++end;
     182
     183      // see if we found our function name
     184      if(*begin && *end){
     185        *begin++ = 0;
     186        *end = 0;
     187        // use the C++ demangler
     188
     189        size_t sz = entry_t::info_t::length2;
     190        int status;
     191        char *func_ret = abi::__cxa_demangle(begin, dm_function, &sz, &status);
     192        if(func_ret){
     193          // abi might have realloced...
     194          dm_function = func_ret;
     195          func_name = dm_function;
     196        }
     197        else{
     198          // demangling failed... get the function name without demangling
     199          func_name = begin;
     200        }
     201      }
     202      else{
     203        // function name not found... get the whole line
     204        func_name = stack_strings[max_depth-1];
     205      }
     206
     207    }
     208    else{
     209      func_name = toplevel;
     210    }
     211
     212    // now we copy the desired function name
     213    if((retval = static_cast<char*>(malloc(strlen(func_name)+1)))){
     214      // we know that the string will fit, so strcpy is safe here
     215      strcpy(retval,func_name);
     216    }
     217    else{
     218      free(stack_strings); // malloc()ed by backtrace_symbols
     219      free(dm_function);
     220      // uh-uh ... seems we are out of luck for allocations now
     221      throw std::bad_alloc();
     222    }
     223    free(dm_function);
     224    free(stack_strings); // malloc()ed by backtrace_symbols
     225    return retval;
     226  }
     227#endif
     228}
     229
     230#ifdef __GNUC__
     231
     232void *operator new(size_t nbytes,const char* file, int line, const char* func) throw(std::bad_alloc) {
     233
     234  // we need to lock, so that no one changes the linked list while we are here
     235  boost::mutex::scoped_lock guard(Memory::memorylock);
     236
     237  // to avoid allocations of 0 bytes if someone screws up
     238  // allocation with 0 byte size are undefined behavior, so we are
     239  // free to handle it this way
     240  if(!nbytes) {
     241    nbytes = 1;
     242  }
     243
     244  // get the size of the entry, including alignment
     245  static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t));
     246
     247  void *res;
     248  if(!(res=malloc(entrySpace + nbytes))){
     249    // new must throw, when space is low
     250    throw std::bad_alloc();
     251  }
     252
     253  // we got the space, so update the global info
     254  Memory::state += nbytes;
     255  if(Memory::state>Memory::max){
     256    Memory::max = Memory::state;
     257  }
     258  Memory::allocs++;
     259
     260  // build the entry in front of the space
     261  Memory::entry_t *entry = (Memory::entry_t*) res;
     262  memset(res,0,entrySpace);
     263  entry->info.nbytes = nbytes;
     264  entry->info.isUsed = true;
     265  strncpy(entry->info.file,file,Memory::entry_t::info_t::length);
     266  entry->info.file[Memory::entry_t::info_t::length] = '\0';
     267  entry->info.line=line;
     268  strncpy(entry->info.function,func,Memory::entry_t::info_t::length2);
     269  entry->info.function[Memory::entry_t::info_t::length2] = '\0';
     270  // the space starts behind the info
     271  entry->info.location = (char*)res + entrySpace;
     272
     273  // add the entry at the end of the list
     274  entry->next=0;            // the created block is last in the list
     275  entry->prev=Memory::end;  // the created block is last in the list
     276  if(!Memory::begin){
     277    // the list was empty... start a new one
     278    Memory::begin=entry;
     279  }
     280  else {
     281    // other blocks present... we can add to the last one
     282    Memory::end->next=entry;
     283  }
     284  Memory::end=entry;
     285
     286  // get the checksum...
     287  entry->checksum = Memory::calcChecksum(&entry->info);
     288  // this will be set to true, when the block is removed from
     289  // the list for any reason
     290  entry->isIgnored = false;
     291
     292  // ok, space is prepared... the user can have it.
     293  // the rest (constructor, deleting when something is thrown etc)
     294  // is handled automatically
     295  return entry->info.location;
     296}
     297
     298#else
    133299
    134300void *operator new(size_t nbytes,const char* file, int line) throw(std::bad_alloc) {
     
    196362}
    197363
     364#endif
     365
    198366void *operator new(size_t nbytes) throw(std::bad_alloc) {
    199367  // Just forward to the other operator, when we do not know from
    200368  // where the allocation came
     369#ifdef __GNUC__
     370  // this might throw bad_alloc
     371  char *caller = Memory::getCaller();
     372  void* retval = 0;
     373
     374  // if this throws, we have to clean up the caller anyway
     375  try{
     376    retval = operator new(nbytes,"Unknown",0,caller);
     377  }
     378  catch(...)
     379  {
     380    free(caller); // malloc()ed by Memory::getCaller();
     381    throw;
     382  }
     383  free(caller); // malloc()ed by Memory::getCaller();
     384  return retval;
     385#else
    201386  return operator new(nbytes,"Unknown",0);
    202 }
     387#endif
     388}
     389
     390#ifdef __GNUC__
     391
     392void *operator new[] (size_t nbytes,const char* file, int line, const char* func) throw(std::bad_alloc) {
     393  // The difference between new and new[] is just for compiler bookkeeping.
     394  return operator new(nbytes,file,line,func);
     395}
     396
     397#else
    203398
    204399void *operator new[] (size_t nbytes,const char* file, int line) throw(std::bad_alloc) {
     
    207402}
    208403
     404#endif
     405
    209406void *operator new[] (size_t nbytes) throw(std::bad_alloc) {
    210407  // Forward again
     408#ifdef __GNUC__
     409  // this might throw bad_alloc
     410    char *caller = Memory::getCaller();
     411    void *retval=0;
     412
     413    // if this throws, we have to clean up the caller anyway
     414    try{
     415      retval = operator new[] (nbytes,"Unknown",0,caller);
     416    }
     417    catch(...)
     418    {
     419      free(caller); // malloc()ed by Memory::getCaller();
     420      throw;
     421    }
     422    free(caller); // malloc()ed by Memory::getCaller();
     423    return retval;
     424#else
    211425  return operator new[] (nbytes,"Unknown",0);
     426#endif
    212427}
    213428
Note: See TracChangeset for help on using the changeset viewer.