Wm4Memory.cpp

Go to the documentation of this file.
00001 // Wild Magic Source Code
00002 // David Eberly
00003 // http://www.geometrictools.com
00004 // Copyright (c) 1998-2007
00005 //
00006 // This library is free software; you can redistribute it and/or modify it
00007 // under the terms of the GNU Lesser General Public License as published by
00008 // the Free Software Foundation; either version 2.1 of the License, or (at
00009 // your option) any later version.  The license is available for reading at
00010 // either of the locations:
00011 //     http://www.gnu.org/copyleft/lgpl.html
00012 //     http://www.geometrictools.com/License/WildMagicLicense.pdf
00013 // The license applies to versions 0 through 4 of Wild Magic.
00014 //
00015 // Version: 4.0.0 (2006/06/28)
00016 
00017 #include "Wm4FoundationPCH.h"
00018 
00019 #ifdef WM4_MEMORY_MANAGER
00020 
00021 // Enable this #define if you want to trap mismatches of new/delete[] or
00022 // new[]/delete.  Xcode 2.3 has mismatches of this form in its STL.  For
00023 // example, Program::Load creates a std::ifstream called kIStr.  At the end
00024 // of that function call, kIStr.close() triggers an assert in the function
00025 // Memory::Deallocate because pkBlock->IsArray is 'false' but 'bIsArray' is
00026 // true.  This implies a mismatch of new/delete[].
00027 //#define WM4_ENABLE_NEW_DELETE_MISMATCH_ASSERT
00028 
00029 // Enable this #define the consistency checks in Memory::GenerateReport.
00030 // Xcode 2.3 triggers the last assert in this function.  It appears that
00031 // Xcode's standard libraries have lots of leaks.
00032 //#define WM4_ENABLE_CONSISTENCY_CHECK
00033 
00034 #include <cassert>
00035 #include <cstdlib>
00036 #include <fstream>
00037 #include "Wm4Memory.h"
00038 using namespace Wm4;
00039 
00040 size_t Memory::ms_uiNumNewCalls = 0;
00041 size_t Memory::ms_uiNumDeleteCalls = 0;
00042 size_t Memory::ms_uiMaxAllowedBytes = 0;
00043 size_t Memory::ms_uiNumBlocks = 0;
00044 size_t Memory::ms_uiNumBytes = 0;
00045 Memory::Block* Memory::ms_pkHead = 0;
00046 Memory::Block* Memory::ms_pkTail = 0;
00047 bool Memory::ms_bTrackSizes = false;
00048 size_t Memory::ms_uiMaxAllocatedBytes = 0;
00049 size_t Memory::ms_uiMaxBlockSize = 0;
00050 size_t Memory::ms_auiHistogram[32] =
00051 {
00052     0,0,0,0,0,0,0,0,
00053     0,0,0,0,0,0,0,0,
00054     0,0,0,0,0,0,0,0,
00055     0,0,0,0,0,0,0,0
00056 };
00057 
00058 //----------------------------------------------------------------------------
00059 void* Memory::Allocate (size_t uiSize, char* acFile, unsigned int uiLine,
00060     bool bIsArray)
00061 {
00062     ms_uiNumNewCalls++;
00063 
00064     // The 'assert' used to be enabled to trap attempts to allocate zero
00065     // bytes.  However, the DirectX function D3DXCheckNewDelete may pass in
00066     // a value of zero.
00067     // assert(uiSize > 0);
00068 
00069     // Allocate additional storage for the block header information.
00070     size_t uiExtendedSize = sizeof(Block) + uiSize;
00071     char* pcAddr = (char*)malloc(uiExtendedSize);
00072 
00073     // Save the allocation information.
00074     Block* pkBlock = (Block*)pcAddr;
00075     pkBlock->Size = uiSize;
00076     pkBlock->File = acFile;
00077     pkBlock->Line = uiLine;
00078     pkBlock->IsArray = bIsArray;
00079     InsertBlock(pkBlock);
00080 
00081     // Move the pointer to the start of what the user expects from 'new'.
00082     pcAddr += sizeof(Block);
00083 
00084     // Keep track of number of allocated blocks and bytes.
00085     ms_uiNumBlocks++;
00086     ms_uiNumBytes += uiSize;
00087 
00088     if (ms_uiMaxAllowedBytes > 0 && ms_uiNumBytes > ms_uiMaxAllowedBytes)
00089     {
00090         // The allocation has exceeded the maximum number of bytes.
00091         assert(false);
00092     }
00093 
00094     // Keep track of the maximum number of bytes allocated.
00095     if (ms_uiNumBytes > ms_uiMaxAllocatedBytes)
00096     {
00097         ms_uiMaxAllocatedBytes = ms_uiNumBytes;
00098     }
00099 
00100     // Keep track of the distribution of sizes for allocations.
00101     if (ms_bTrackSizes)
00102     {
00103         // Keep track of the largest block ever allocated.
00104         if (uiSize > ms_uiMaxBlockSize)
00105         {
00106             ms_uiMaxBlockSize = uiSize;
00107         }
00108 
00109         unsigned int uiTwoPowerI = 1;
00110         int i;
00111         for (i = 0; i <= 30; i++, uiTwoPowerI <<= 1)
00112         {
00113             if (uiSize <= uiTwoPowerI)
00114             {
00115                 ms_auiHistogram[i]++;
00116                 break;
00117             }
00118         }
00119         if (i == 31)
00120         {
00121             ms_auiHistogram[i]++;
00122         }
00123     }
00124 
00125     return (void*)pcAddr;
00126 }
00127 //----------------------------------------------------------------------------
00128 void Memory::Deallocate (char* pcAddr, bool bIsArray)
00129 {
00130     ms_uiNumDeleteCalls++;
00131 
00132     if (!pcAddr)
00133     {
00134         return;
00135     }
00136 
00137     // Move the pointer to the start of the actual allocated block.
00138     pcAddr -= sizeof(Block);
00139 
00140     // Get the allocation information and remove the block.  The removal
00141     // only modifies the Prev and Next pointers, so the block information is
00142     // accessible after the call.
00143     Block* pkBlock = (Block*)pcAddr;
00144     RemoveBlock(pkBlock);
00145 
00146 #ifdef WM4_ENABLE_NEW_DELETE_MISMATCH_ASSERT
00147     // Check for correct pairing of new/delete or new[]/delete[].
00148     assert(pkBlock->IsArray == bIsArray);
00149 #endif
00150 
00151     // Keep track of number of allocated blocks and bytes.  If the number of
00152     // blocks is zero at this time, a delete has been called twice on the
00153     // same pointer.  If the number of bytes is too small at this time, some
00154     // internal problem has occurred within this class and needs to be
00155     // diagnosed.
00156     assert(ms_uiNumBlocks > 0 && ms_uiNumBytes >= pkBlock->Size);
00157     ms_uiNumBlocks--;
00158     ms_uiNumBytes -= pkBlock->Size;
00159 
00160     // Deallocate the memory block.
00161     free(pcAddr);
00162 }
00163 //----------------------------------------------------------------------------
00164 void Memory::InsertBlock (Block* pkBlock)
00165 {
00166     // New blocks are inserted at the tail of the doubly linked list.
00167     if (ms_pkTail)
00168     {
00169         pkBlock->Prev = ms_pkTail;
00170         pkBlock->Next = 0;
00171         ms_pkTail->Next = pkBlock;
00172         ms_pkTail = pkBlock;
00173     }
00174     else
00175     {
00176         pkBlock->Prev = 0;
00177         pkBlock->Next = 0;
00178         ms_pkHead = pkBlock;
00179         ms_pkTail = pkBlock;
00180     }
00181 }
00182 //----------------------------------------------------------------------------
00183 void Memory::RemoveBlock (Block* pkBlock)
00184 {
00185     if (pkBlock->Prev)
00186     {
00187         pkBlock->Prev->Next = pkBlock->Next;
00188     }
00189     else
00190     {
00191         ms_pkHead = pkBlock->Next;
00192     }
00193     
00194     if (pkBlock->Next)
00195     {
00196         pkBlock->Next->Prev = pkBlock->Prev;
00197     }
00198     else
00199     {
00200         ms_pkTail = pkBlock->Prev;
00201     }
00202 }
00203 //----------------------------------------------------------------------------
00204 void Memory::GenerateReport (const char* acFilename)
00205 {
00206     std::ofstream kOStr(acFilename);
00207     assert(kOStr);
00208     if (!kOStr)
00209     {
00210         return;
00211     }
00212 
00213     // Total calls.
00214     kOStr << "Total number of 'new' calls = "
00215         << (unsigned int)ms_uiNumNewCalls << std::endl;
00216     kOStr << "Total number of 'delete' calls = "
00217         << (unsigned int)ms_uiNumDeleteCalls << std::endl;
00218     kOStr << "Maximum number of allocated bytes = "
00219         << (unsigned int)ms_uiMaxAllocatedBytes << std::endl << std::endl;
00220 
00221     // Remaining counts.
00222     kOStr << "Remaining number of blocks = "
00223         << (unsigned int)ms_uiNumBlocks << std::endl;
00224     kOStr << "Remaining number of bytes  = "
00225         << (unsigned int)ms_uiNumBytes << std::endl << std::endl;
00226 
00227     // Count the blocks and bytes from known and unknown sources.
00228     size_t uiNumKnownBlocks = 0;
00229     size_t uiNumKnownBytes = 0;
00230     size_t uiNumUnknownBlocks = 0;
00231     size_t uiNumUnknownBytes = 0;
00232     Block* pkBlock = ms_pkHead;
00233     while (pkBlock)
00234     {
00235         if (pkBlock->File)
00236         {
00237             uiNumKnownBlocks++;
00238             uiNumKnownBytes += pkBlock->Size;
00239         }
00240         else
00241         {
00242             uiNumUnknownBlocks++;
00243             uiNumUnknownBytes += pkBlock->Size;
00244         }
00245         pkBlock = pkBlock->Next;
00246     }
00247 
00248 #ifdef WM4_ENABLE_CONSISTENCY_CHECK
00249     // consistency check
00250     assert(uiNumKnownBlocks + uiNumUnknownBlocks == ms_uiNumBlocks);
00251     assert(uiNumKnownBytes + uiNumUnknownBytes == ms_uiNumBytes);
00252 #endif
00253 
00254     kOStr << "Remaining number of known blocks = "
00255         << (unsigned int)uiNumKnownBlocks << std::endl;
00256     kOStr << "Remaining number of known bytes  = "
00257         << (unsigned int)uiNumKnownBytes << std::endl << std::endl;
00258 
00259     kOStr << "Remaining number of unknown blocks = "
00260         << (unsigned int)uiNumUnknownBlocks << std::endl;
00261     kOStr << "Remaining number of unknown bytes  = "
00262         << (unsigned int)uiNumUnknownBytes << std::endl << std::endl;
00263 
00264     // Report the information for each block.
00265     pkBlock = ms_pkHead;
00266     size_t uiIndex = 0;
00267     while (pkBlock)
00268     {
00269         kOStr << "block = " << (unsigned int)uiIndex << std::endl;
00270         kOStr << "size  = " << (unsigned int)pkBlock->Size << std::endl;
00271         if (pkBlock->File)
00272         {
00273             kOStr << "file  = " << pkBlock->File << std::endl;
00274             kOStr << "line  = " << pkBlock->Line << std::endl;
00275         }
00276         else
00277         {
00278             kOStr << "file  = unknown" << std::endl;
00279             kOStr << "line  = unknown" << std::endl;
00280         }
00281         kOStr << "array = " << pkBlock->IsArray << std::endl << std::endl;
00282         pkBlock = pkBlock->Next;
00283         uiIndex++;
00284     }
00285     kOStr.close();
00286 
00287 #ifdef WM4_ENABLE_CONSISTENCY_CHECK
00288     // consistency check
00289     assert(uiIndex == ms_uiNumBlocks);
00290 #endif
00291 }
00292 //----------------------------------------------------------------------------
00293 void* operator new (size_t uiSize)
00294 {
00295     return Memory::Allocate(uiSize,0,0,false);
00296 }
00297 //----------------------------------------------------------------------------
00298 void* operator new[](size_t uiSize)
00299 {
00300     return Memory::Allocate(uiSize,0,0,true);
00301 }
00302 //----------------------------------------------------------------------------
00303 void* operator new (size_t uiSize, char* acFile, unsigned int uiLine)
00304 {
00305     return Memory::Allocate(uiSize,acFile,uiLine,false);
00306 }
00307 //----------------------------------------------------------------------------
00308 void* operator new[] (size_t uiSize, char* acFile, unsigned int uiLine)
00309 {
00310     return Memory::Allocate(uiSize,acFile,uiLine,true);
00311 }
00312 //----------------------------------------------------------------------------
00313 void operator delete (void* pvAddr)
00314 {
00315     Memory::Deallocate((char*)pvAddr,false);
00316 }
00317 //----------------------------------------------------------------------------
00318 void operator delete[] (void* pvAddr)
00319 {
00320     Memory::Deallocate((char*)pvAddr,true);
00321 }
00322 //----------------------------------------------------------------------------
00323 void operator delete (void* pvAddr, char*, unsigned int)
00324 {
00325     Memory::Deallocate((char*)pvAddr,false);
00326 }
00327 //----------------------------------------------------------------------------
00328 void operator delete[] (void* pvAddr, char*, unsigned int)
00329 {
00330     Memory::Deallocate((char*)pvAddr,true);
00331 }
00332 //----------------------------------------------------------------------------
00333 
00334 #endif

Generated on Wed Nov 23 19:01:06 2011 for FreeCAD by  doxygen 1.6.1