TStorage.cxx

Go to the documentation of this file.
00001 // @(#)root/base:$Id: TStorage.cxx 34286 2010-07-01 20:38:57Z rdm $
00002 // Author: Fons Rademakers   29/07/95
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TStorage                                                             //
00015 //                                                                      //
00016 // Storage manager. The storage manager works best in conjunction with  //
00017 // the custom ROOT new and delete operators defined in the file         //
00018 // NewDelete.cxx (libNew.so). Only when using the custom allocation     //
00019 // operators will memory usage statistics be gathered using the         //
00020 // TStorage EnterStat(), RemoveStat(), etc. functions.                  //
00021 // Memory checking is by default enabled (when using libNew.so) and     //
00022 // usage statistics is gathered. Using the resource (in .rootrc):       //
00023 // Root.MemStat one can toggle statistics gathering on or off. More     //
00024 // specifically on can trap the allocation of a block of memory of a    //
00025 // certain size. This can be specified using the resource:              //
00026 // Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
00027 // specify after how many allocations of this size the trap should      //
00028 // occur.                                                               //
00029 // Set the compile option R__NOSTATS to de-activate all memory checking //
00030 // and statistics gathering in the system.                              //
00031 //                                                                      //
00032 //////////////////////////////////////////////////////////////////////////
00033 
00034 #include <stdlib.h>
00035 
00036 #include "TROOT.h"
00037 #include "TObjectTable.h"
00038 #include "TError.h"
00039 #include "TString.h"
00040 #include "TVirtualMutex.h"
00041 #include "TInterpreter.h"
00042 
00043 #if !defined(R__NOSTATS)
00044 #   define MEM_DEBUG
00045 #   define MEM_STAT
00046 #   define MEM_CHECKOBJECTPOINTERS
00047 #endif
00048 
00049 #if defined(MEM_STAT) && !defined(MEM_DEBUG)
00050 #   define MEM_DEBUG
00051 #endif
00052 
00053 #ifdef MEM_DEBUG
00054 #   ifdef R__B64
00055 #      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
00056 #   else
00057 #      define storage_size(p) ((size_t)(((int*)p)[-2]))
00058 #   endif
00059 #else
00060 #   define storage_size(p) ((size_t)0)
00061 #endif
00062 
00063 #define PVOID (-1)
00064 
00065 ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
00066 ULong_t       TStorage::fgHeapEnd;
00067 size_t        TStorage::fgMaxBlockSize;
00068 FreeHookFun_t TStorage::fgFreeHook;
00069 void         *TStorage::fgFreeHookData;
00070 ReAllocFun_t  TStorage::fgReAllocHook;
00071 ReAllocCFun_t TStorage::fgReAllocCHook;
00072 Bool_t        TStorage::fgHasCustomNewDelete;
00073 
00074 
00075 ClassImp(TStorage)
00076 
00077 //------------------------------------------------------------------------------
00078 
00079 static const char *gSpaceErr = "storage exhausted";
00080 
00081 const size_t kObjMaxSize = 10024;
00082 
00083 static Bool_t   gMemStatistics;
00084 static Int_t    gAllocated[kObjMaxSize], gFreed[kObjMaxSize];
00085 static Int_t    gAllocatedTotal, gFreedTotal;
00086 static void   **gTraceArray = 0;
00087 static Int_t    gTraceCapacity = 10, gTraceIndex = 0,
00088                 gMemSize = -1, gMemIndex = -1;
00089 
00090 
00091 //______________________________________________________________________________
00092 void TStorage::EnterStat(size_t size, void *p)
00093 {
00094    // Register a memory allocation operation. If desired one can trap an
00095    // allocation of a certain size in case one tries to find a memory
00096    // leak of that particular size. This function is only called via
00097    // the ROOT custom new operators.
00098 
00099    TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));
00100 
00101    if (!gMemStatistics) return;
00102 
00103    if ((Int_t)size == gMemSize) {
00104       if (gTraceIndex == gMemIndex)
00105          Fatal("EnterStat", "trapped allocation %d", gMemIndex);
00106 
00107       if (!gTraceArray)
00108          gTraceArray = (void**) malloc(sizeof(void*)*gTraceCapacity);
00109 
00110       if (gTraceIndex >= gTraceCapacity) {
00111          gTraceCapacity = gTraceCapacity*2;
00112          gTraceArray = (void**) realloc(gTraceArray, sizeof(void*)*gTraceCapacity);
00113       }
00114       gTraceArray[gTraceIndex++] = p;
00115    }
00116    if (size >= kObjMaxSize)
00117       gAllocated[kObjMaxSize-1]++;
00118    else
00119       gAllocated[size]++;
00120    gAllocatedTotal += size;
00121 }
00122 
00123 //______________________________________________________________________________
00124 void TStorage::RemoveStat(void *vp)
00125 {
00126    // Register a memory free operation. This function is only called via
00127    // the custom ROOT delete operator.
00128 
00129    if (!gMemStatistics) return;
00130 
00131    size_t size = storage_size(vp);
00132    if ((Int_t)size == gMemSize) {
00133       for (int i = 0; i < gTraceIndex; i++)
00134          if (gTraceArray[i] == vp) {
00135             gTraceArray[i] = 0;
00136             break;
00137          }
00138    }
00139    if (size >= kObjMaxSize)
00140       gFreed[kObjMaxSize-1]++;
00141    else
00142       gFreed[size]++;
00143    gFreedTotal += size;
00144 }
00145 
00146 //______________________________________________________________________________
00147 void *TStorage::Alloc(size_t size)
00148 {
00149    // Allocate a block of memory, that later can be resized using
00150    // TStorage::ReAlloc().
00151 
00152    static const char *where = "TStorage::Alloc";
00153 
00154 #ifndef WIN32
00155    void *vp = ::operator new[](size);
00156 #else
00157    void *vp = ::operator new(size);
00158 #endif
00159    if (vp == 0)
00160       Fatal(where, "%s", gSpaceErr);
00161 
00162    return vp;
00163 }
00164 
00165 //______________________________________________________________________________
00166 void TStorage::Dealloc(void *ptr)
00167 {
00168    // De-allocate block of memory, that was allocated via TStorage::Alloc().
00169 
00170 #ifndef WIN32
00171    ::operator delete[](ptr);
00172 #else
00173    ::operator delete(ptr);
00174 #endif
00175 }
00176 
00177 //______________________________________________________________________________
00178 void *TStorage::ReAlloc(void *ovp, size_t size)
00179 {
00180    // Reallocate (i.e. resize) block of memory.
00181 
00182    // Needs to be protected by global mutex
00183    R__LOCKGUARD(gGlobalMutex);
00184 
00185    if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck())
00186       return (*fgReAllocHook)(ovp, size);
00187 
00188    static const char *where = "TStorage::ReAlloc";
00189 
00190 #ifndef WIN32
00191    void *vp = ::operator new[](size);
00192 #else
00193    void *vp = ::operator new(size);
00194 #endif
00195    if (vp == 0)
00196       Fatal(where, "%s", gSpaceErr);
00197 
00198    if (ovp == 0)
00199       return vp;
00200 
00201    memmove(vp, ovp, size);
00202 #ifndef WIN32
00203    ::operator delete[](ovp);
00204 #else
00205    ::operator delete(ovp);
00206 #endif
00207    return vp;
00208 }
00209 
00210 //______________________________________________________________________________
00211 void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
00212 {
00213    // Reallocate (i.e. resize) block of memory. Checks if current size is
00214    // equal to oldsize. If not memory was overwritten.
00215 
00216    // Needs to be protected by global mutex
00217    R__LOCKGUARD(gGlobalMutex);
00218 
00219    if (fgReAllocCHook && fgHasCustomNewDelete && !TROOT::MemCheck())
00220       return (*fgReAllocCHook)(ovp, size, oldsize);
00221 
00222    static const char *where = "TStorage::ReAlloc";
00223 
00224    if (oldsize == size)
00225       return ovp;
00226 
00227 #ifndef WIN32
00228    void *vp = ::operator new[](size);
00229 #else
00230    void *vp = ::operator new(size);
00231 #endif
00232    if (vp == 0)
00233       Fatal(where, "%s", gSpaceErr);
00234 
00235    if (ovp == 0)
00236       return vp;
00237 
00238    if (size > oldsize) {
00239       memcpy(vp, ovp, oldsize);
00240       memset((char*)vp+oldsize, 0, size-oldsize);
00241    } else
00242       memcpy(vp, ovp, size);
00243 #ifndef WIN32
00244    ::operator delete[](ovp);
00245 #else
00246    ::operator delete(ovp);
00247 #endif
00248    return vp;
00249 }
00250 
00251 //______________________________________________________________________________
00252 char *TStorage::ReAllocChar(char *ovp, size_t size, size_t oldsize)
00253 {
00254    // Reallocate (i.e. resize) array of chars. Size and oldsize are
00255    // in number of chars.
00256 
00257    // Needs to be protected by global mutex
00258    R__LOCKGUARD(gGlobalMutex);
00259 
00260    static const char *where = "TStorage::ReAllocChar";
00261 
00262    char *vp;
00263    if (ovp == 0) {
00264       vp = new char[size];
00265       if (vp == 0)
00266          Fatal(where, "%s", gSpaceErr);
00267       return vp;
00268    }
00269    if (oldsize == size)
00270       return ovp;
00271 
00272    vp = new char[size];
00273    if (vp == 0)
00274       Fatal(where, "%s", gSpaceErr);
00275    if (size > oldsize) {
00276       memcpy(vp, ovp, oldsize);
00277       memset((char*)vp+oldsize, 0, size-oldsize);
00278    } else
00279       memcpy(vp, ovp, size);
00280    delete [] ovp;
00281    return vp;
00282 }
00283 
00284 //______________________________________________________________________________
00285 Int_t *TStorage::ReAllocInt(Int_t *ovp, size_t size, size_t oldsize)
00286 {
00287    // Reallocate (i.e. resize) array of integers. Size and oldsize are
00288    // number of integers (not number of bytes).
00289 
00290    // Needs to be protected by global mutex
00291    R__LOCKGUARD(gGlobalMutex);
00292 
00293    static const char *where = "TStorage::ReAllocInt";
00294 
00295    Int_t *vp;
00296    if (ovp == 0) {
00297       vp = new Int_t[size];
00298       if (vp == 0)
00299          Fatal(where, "%s", gSpaceErr);
00300       return vp;
00301    }
00302    if (oldsize == size)
00303       return ovp;
00304 
00305    vp = new Int_t[size];
00306    if (vp == 0)
00307       Fatal(where, "%s", gSpaceErr);
00308    if (size > oldsize) {
00309       memcpy(vp, ovp, oldsize*sizeof(Int_t));
00310       memset((Int_t*)vp+oldsize, 0, (size-oldsize)*sizeof(Int_t));
00311    } else
00312       memcpy(vp, ovp, size*sizeof(Int_t));
00313    delete [] ovp;
00314    return vp;
00315 }
00316 
00317 //______________________________________________________________________________
00318 void *TStorage::ObjectAlloc(size_t sz)
00319 {
00320    // Used to allocate a TObject on the heap (via TObject::operator new()).
00321    // Directly after this routine one can call (in the TObject ctor)
00322    // TStorage::IsOnHeap() to find out if the just created object is on
00323    // the heap.
00324 
00325    // Needs to be protected by global mutex
00326    R__LOCKGUARD(gGlobalMutex);
00327 
00328    ULong_t space = (ULong_t) ::operator new(sz);
00329    AddToHeap(space, space+sz);
00330    return (void*) space;
00331 }
00332 
00333 //______________________________________________________________________________
00334 void *TStorage::ObjectAlloc(size_t , void *vp)
00335 {
00336    // Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
00337    // in position vp. vp is already allocated (maybe on heap, maybe on
00338    // stack) so just return.
00339 
00340    return vp;
00341 }
00342 
00343 //______________________________________________________________________________
00344 void TStorage::ObjectDealloc(void *vp)
00345 {
00346    // Used to deallocate a TObject on the heap (via TObject::operator delete()).
00347 
00348    // Needs to be protected by global mutex
00349    R__LOCKGUARD(gGlobalMutex);
00350 
00351 #ifndef NOCINT
00352    // to handle delete with placement called via CINT
00353    Long_t gvp = 0;
00354    if (gCint) gvp = gCint->Getgvp();
00355    if ((Long_t)vp == gvp && gvp != (Long_t)PVOID)
00356       return;
00357 #endif
00358    ::operator delete(vp);
00359 }
00360 
00361 //______________________________________________________________________________
00362 void TStorage::ObjectDealloc(void *vp, void *ptr)
00363 {
00364    // Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).
00365 
00366    if (vp && ptr) { }
00367 }
00368 
00369 //______________________________________________________________________________
00370 void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
00371 {
00372    // Set a free handler.
00373 
00374    fgFreeHook     = fh;
00375    fgFreeHookData = data;
00376 }
00377 
00378 //______________________________________________________________________________
00379 void TStorage::SetReAllocHooks(ReAllocFun_t rh1, ReAllocCFun_t rh2)
00380 {
00381    // Set a custom ReAlloc handlers. This function is typically
00382    // called via a static object in the ROOT libNew.so shared library.
00383 
00384    fgReAllocHook  = rh1;
00385    fgReAllocCHook = rh2;
00386 }
00387 
00388 //______________________________________________________________________________
00389 void TStorage::PrintStatistics()
00390 {
00391    // Print memory usage statistics.
00392 
00393    // Needs to be protected by global mutex
00394    R__LOCKGUARD(gGlobalMutex);
00395 
00396 #if defined(MEM_DEBUG) && defined(MEM_STAT)
00397 
00398    if (!gMemStatistics || !HasCustomNewDelete())
00399       return;
00400 
00401    //Printf("");
00402    Printf("Heap statistics");
00403    Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
00404    Printf("================================================");
00405 
00406    int i;
00407    for (i = 0; i < (int)kObjMaxSize; i++)
00408       if (gAllocated[i] != gFreed[i])
00409       //if (gAllocated[i])
00410          Printf("%12d%12d%12d%12d", i, gAllocated[i], gFreed[i],
00411                 gAllocated[i]-gFreed[i]);
00412 
00413    if (gAllocatedTotal != gFreedTotal) {
00414       Printf("------------------------------------------------");
00415       Printf("Total:      %12d%12d%12d", gAllocatedTotal, gFreedTotal,
00416               gAllocatedTotal-gFreedTotal);
00417    }
00418 
00419    if (gMemSize != -1) {
00420       Printf("------------------------------------------------");
00421       for (i= 0; i < gTraceIndex; i++)
00422          if (gTraceArray[i])
00423             Printf("block %d of size %d not freed", i, gMemSize);
00424    }
00425    Printf("================================================");
00426    Printf(" ");
00427 #endif
00428 }
00429 
00430 //______________________________________________________________________________
00431 void TStorage::EnableStatistics(int size, int ix)
00432 {
00433    // Enable memory usage statistics gathering. Size is the size of the memory
00434    // block that should be trapped and ix is after how many such allocations
00435    // the trap should happen.
00436 
00437 #ifdef MEM_STAT
00438    gMemSize       = size;
00439    gMemIndex      = ix;
00440    gMemStatistics = kTRUE;
00441 #else
00442    int idum = size; int iidum = ix;
00443 #endif
00444 }
00445 
00446 //______________________________________________________________________________
00447 ULong_t TStorage::GetHeapBegin()
00448 {
00449    //return begin of heap
00450    return fgHeapBegin;
00451 }
00452 
00453 //______________________________________________________________________________
00454 ULong_t TStorage::GetHeapEnd()
00455 {
00456    //return end of heap
00457    return fgHeapEnd;
00458 }
00459 
00460 //______________________________________________________________________________
00461 void *TStorage::GetFreeHookData()
00462 {
00463    //return static free hook data
00464    return fgFreeHookData;
00465 }
00466 
00467 //______________________________________________________________________________
00468 Bool_t TStorage::HasCustomNewDelete()
00469 {
00470    //return the has custom delete flag
00471    return fgHasCustomNewDelete;
00472 }
00473 
00474 //______________________________________________________________________________
00475 void TStorage::SetCustomNewDelete()
00476 {
00477    //set the has custom delete flag
00478    fgHasCustomNewDelete = kTRUE;
00479 }
00480 
00481 #ifdef WIN32
00482 
00483 //______________________________________________________________________________
00484 void TStorage::AddToHeap(ULong_t begin, ULong_t end)
00485 {
00486    //add a range to the heap
00487    if (begin < fgHeapBegin) fgHeapBegin = begin;
00488    if (end   > fgHeapEnd)   fgHeapEnd   = end;
00489 }
00490 
00491 //______________________________________________________________________________
00492 Bool_t TStorage::IsOnHeap(void *p)
00493 {
00494    //is object at p in the heap?
00495    return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd;
00496 }
00497 
00498 //______________________________________________________________________________
00499 size_t TStorage::GetMaxBlockSize()
00500 {
00501    //return max block size
00502    return fgMaxBlockSize;
00503 }
00504 
00505 //______________________________________________________________________________
00506 void TStorage::SetMaxBlockSize(size_t size)
00507 {
00508    //set max block size
00509    fgMaxBlockSize = size;
00510 }
00511 
00512 //______________________________________________________________________________
00513 FreeHookFun_t TStorage::GetFreeHook()
00514 {
00515    //return free hook
00516    return fgFreeHook;
00517 }
00518 
00519 #endif

Generated on Tue Jul 5 14:11:23 2011 for ROOT_528-00b_version by  doxygen 1.5.1