Changeset 6d6b54 for src/Helpers/MemDebug.cpp
- Timestamp:
- Jun 10, 2010, 3:10:19 PM (15 years ago)
- 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
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Helpers/MemDebug.cpp
r112b09 r6d6b54 10 10 #include <cstring> 11 11 #include <boost/thread.hpp> 12 13 #ifdef __GNUC__ 14 #include <execinfo.h> 15 #include <cxxabi.h> 16 #endif 12 17 13 18 using namespace std; … … 34 39 char file[length+1]; 35 40 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 36 46 size_t nbytes; 37 47 bool isUsed; … … 96 106 for(entry_t *pos=begin;pos;pos=pos->next){ 97 107 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 98 112 cout << "Chunk reserved at: " << pos->info.file << ":" << pos->info.line << endl; 113 #endif 99 114 } 100 115 } … … 130 145 deleteEntry(entry); 131 146 } 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 232 void *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 133 299 134 300 void *operator new(size_t nbytes,const char* file, int line) throw(std::bad_alloc) { … … 196 362 } 197 363 364 #endif 365 198 366 void *operator new(size_t nbytes) throw(std::bad_alloc) { 199 367 // Just forward to the other operator, when we do not know from 200 368 // 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 201 386 return operator new(nbytes,"Unknown",0); 202 } 387 #endif 388 } 389 390 #ifdef __GNUC__ 391 392 void *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 203 398 204 399 void *operator new[] (size_t nbytes,const char* file, int line) throw(std::bad_alloc) { … … 207 402 } 208 403 404 #endif 405 209 406 void *operator new[] (size_t nbytes) throw(std::bad_alloc) { 210 407 // 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 211 425 return operator new[] (nbytes,"Unknown",0); 426 #endif 212 427 } 213 428
Note:
See TracChangeset
for help on using the changeset viewer.