source: XIOS/dev/dev_ym/XIOS_COUPLING/src/memtrack.cpp @ 2230

Last change on this file since 2230 was 2212, checked in by ymipsl, 3 years ago

Revisiting Memory tracking :

  • MemTrack? has been improved
    • Not need anymore to use private external libaddr2line, fork addr2line process internaly and use bidrectionnale pipe to send stack adress et get in return the demangle stack name
    • Can use cxa_demangle in backup
  • Block memory leak report is output in separate file (xios_xxx.mem),memory block are ordonned in decreasing size.
  • Possibility to output only the n bigest bloc with : "memtrack_blocs" xios parameters
  • Possibility to output only bloc over a given size with : "memtrack_size" xios parameters
  • Implement new method to retrieve the memory consumed in a time interval very similarely to xios timer :

CMemTracker("xios").resume()
CMemTracker("xios").suspend() ;
etc....

YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:eol-style set to native
File size: 23.5 KB
Line 
1#ifdef XIOS_MEMTRACK
2/*
3Copyright (c) 2002, 2008 Curtis Bartley
4All rights reserved.
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions
7are met:
8
9- Redistributions of source code must retain the above copyright
10notice, this list of conditions and the following disclaimer.
11
12- Redistributions in binary form must reproduce the above copyright
13notice, this list of conditions and the following disclaimer in the
14documentation and/or other materials provided with the
15distribution.
16
17- Neither the name of Curtis Bartley nor the names of any other
18contributors may be used to endorse or promote products derived
19from this software without specific prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
32OF THE POSSIBILITY OF SUCH DAMAGE.
33*/
34
35/* ---------------------------------------- includes */
36
37#include <assert.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <algorithm>
41#include <cstring>
42#include <new>
43#include <iostream>
44#include <sstream>
45#include <string>
46#include <execinfo.h>
47#include <cxxabi.h>
48#include <dlfcn.h>
49#include <map>
50#include <fstream>
51#include "memtrack.hpp"
52#include "log.hpp"
53#include "addr2line.hpp"
54#undef new    // IMPORTANT!
55
56
57/* ------------------------------------------------------------ */
58/* -------------------- namespace MemTrack -------------------- */
59/* ------------------------------------------------------------ */
60
61namespace MemTrack
62{
63    size_t currentMemorySize=0 ;
64    size_t maxMemorySize=0 ; 
65
66    size_t getCurrentMemorySize(void) {return currentMemorySize; }
67    size_t getMaxMemorySize(void) {return maxMemorySize ; }
68
69    /* ------------------------------------------------------------ */
70    /* --------------------- class BlockHeader -------------------- */
71    /* ------------------------------------------------------------ */
72
73    class BlockHeader
74    {
75        private:    // static member variables
76            static BlockHeader *ourFirstNode;
77   
78        private:    // member variables
79            BlockHeader *myPrevNode;
80            BlockHeader *myNextNode;
81            size_t myRequestedSize;
82            char const *myFilename;
83            int myLineNum;
84            char const *myTypeName;
85           
86            size_t stackSize ;
87            void* stackArray[20] ;
88
89        public:     // members
90            BlockHeader(size_t requestedSize);
91            ~BlockHeader();
92       
93            size_t GetRequestedSize() const { return myRequestedSize; }
94            char const *GetFilename() const { return myFilename; }
95            int GetLineNum() const { return myLineNum; }
96            char const *GetTypeName() const { return myTypeName; }
97       
98            void Stamp(char const *filename, int lineNum, char const *typeName);
99            void backTrace(std::ofstream& memReport, xios::CAddr2line& addr2line) ;
100            void backTrace(std::ofstream& memReport) ;
101
102            static void AddNode(BlockHeader *node);
103            static void RemoveNode(BlockHeader *node);
104            static size_t CountBlocks();
105            static void GetBlocks(BlockHeader **blockHeaderPP);
106            static bool TypeGreaterThan(BlockHeader *header1, BlockHeader *header2);
107    };
108
109    /* ---------------------------------------- BlockHeader static member variables */
110
111    BlockHeader *BlockHeader::ourFirstNode = NULL;
112
113    /* ---------------------------------------- BlockHeader constructor */
114
115    BlockHeader::BlockHeader(size_t requestedSize)
116    {
117        myPrevNode = NULL;
118        myNextNode = NULL;
119        myRequestedSize = requestedSize;
120        myFilename = "[unknown]";
121        myLineNum = 0;
122        myTypeName = "[unknown]";
123        stackSize=backtrace(stackArray,20) ;
124    }
125
126    /* ---------------------------------------- BlockHeader destructor */
127
128    BlockHeader::~BlockHeader()
129    {
130    }
131       
132    /* ---------------------------------------- BlockHeader Stamp */
133
134    void BlockHeader::Stamp(char const *filename, int lineNum, char const *typeName)
135    {
136        myFilename = filename;
137        myLineNum = lineNum;
138        myTypeName = typeName;
139    }
140
141
142    void BlockHeader::backTrace(std::ofstream& memReport)
143    {
144        char** strings ;
145        strings = backtrace_symbols(stackArray, this->stackSize);
146        int stackSize=this->stackSize-3 ;
147        char* buffer ;
148        char* outputBuffer ;
149        size_t length=10 ;
150        outputBuffer = (char*) malloc(length) ;
151        int status ;
152        Dl_info info;
153        for(int i=0;i<stackSize;i++) 
154        {
155            if (dladdr(stackArray[i+3], &info))
156            {
157              buffer=abi::__cxa_demangle(info.dli_sname,outputBuffer,&length,&status );
158              if (buffer!=nullptr) 
159              {
160                memReport<<buffer<<std::endl ;
161                outputBuffer=buffer ;
162              }
163              else if (info.dli_sname!=nullptr) memReport<<info.dli_sname<<std::endl ;
164              else memReport<<strings[i+3]<<std::endl ;
165            }
166            else memReport<<strings[i+3]<<std::endl ;
167        }
168        free(buffer) ;
169        free(strings) ;
170    }
171
172    void BlockHeader::backTrace(std::ofstream& memReport, xios::CAddr2line& addr2line)
173    {   
174       
175      int stackSize=this->stackSize-3 ;
176     
177      for(int i=0;i<stackSize;i++)
178      {
179        std::ostringstream address;
180        address << stackArray[i+3];
181        addr2line.write(address.str()) ;
182        std::string out ;
183        addr2line.read(out) ;
184        memReport<<out<<std::endl ;
185      }
186    }
187    /* ---------------------------------------- BlockHeader AddNode */
188
189    void BlockHeader::AddNode(BlockHeader *node)
190    {
191        assert(node != NULL);
192        assert(node->myPrevNode == NULL);
193        assert(node->myNextNode == NULL);
194
195        // If we have at least one node in the list ...       
196        if (ourFirstNode != NULL)
197        {
198            // ... make the new node the first node's predecessor.
199            assert(ourFirstNode->myPrevNode == NULL);
200            ourFirstNode->myPrevNode = node;
201        }
202
203        // Make the first node the new node's succesor.
204        node->myNextNode = ourFirstNode;
205
206        // Make the new node the first node.
207        ourFirstNode = node;
208    }
209
210    /* ---------------------------------------- BlockHeader RemoveNode */
211
212    void BlockHeader::RemoveNode(BlockHeader *node)
213    {
214        assert(node != NULL);
215        assert(ourFirstNode != NULL);
216
217        // If target node is the first node in the list...
218        if (ourFirstNode == node)
219        {
220            // ... make the target node's successor the first node.
221            assert(ourFirstNode->myPrevNode == NULL);
222            ourFirstNode = node->myNextNode;
223        }
224       
225        // Link target node's predecessor, if any, to its successor.
226        if (node->myPrevNode != NULL)
227        {
228            node->myPrevNode->myNextNode = node->myNextNode;
229        }
230       
231        // Link target node's successor, if any, to its predecessor.
232        if (node->myNextNode != NULL)
233        {
234            node->myNextNode->myPrevNode = node->myPrevNode;
235        }
236
237        // Clear target node's previous and next pointers.
238        node->myPrevNode = NULL;
239        node->myNextNode = NULL;
240    }
241
242    /* ---------------------------------------- BlockHeader CountBlocks */
243
244    size_t BlockHeader::CountBlocks()
245    {
246        size_t count = 0;
247        BlockHeader *currNode = ourFirstNode;
248        while (currNode != NULL)
249        {
250            count++;
251            currNode = currNode->myNextNode;
252        }
253        return count;
254    }
255
256    /* ---------------------------------------- BlockHeader GetBlocks */
257
258    void BlockHeader::GetBlocks(BlockHeader **blockHeaderPP)
259    {
260        BlockHeader *currNode = ourFirstNode;
261        while (currNode != NULL)
262        {
263            *blockHeaderPP = currNode;
264            blockHeaderPP++;
265            currNode = currNode->myNextNode;
266        }
267    }
268
269    /* ---------------------------------------- BlockHeader TypeGreaterThan */
270
271    bool BlockHeader::TypeGreaterThan(BlockHeader *header1, BlockHeader *header2)
272    {
273        return (strcmp(header1->myTypeName, header2->myTypeName) > 0);
274    }
275
276    /* ------------------------------------------------------------ */
277    /* ---------------------- class Signature --------------------- */
278    /* ------------------------------------------------------------ */
279
280    class Signature
281    {
282        private:    // constants
283            static const unsigned int SIGNATURE1 = 0xCAFEBABE;
284            static const unsigned int SIGNATURE2 = 0xFACEFACE;
285       
286        private:    // member variables
287            unsigned int mySignature1;
288            unsigned int mySignature2;
289           
290        public:        // construction/destruction
291            Signature() : mySignature1(SIGNATURE1), mySignature2(SIGNATURE2) {};
292            ~Signature() { mySignature1 = 0; mySignature2 = 0; }
293           
294        public:        // static member functions
295            static bool IsValidSignature(const Signature *pProspectiveSignature)
296            {
297                try
298                {
299                    if (pProspectiveSignature->mySignature1 != SIGNATURE1) return false;
300                    if (pProspectiveSignature->mySignature2 != SIGNATURE2) return false;
301                    return true;
302                }
303                catch (...)
304                {
305                    return false;
306                }
307            }
308    };
309
310    /* ------------------------------------------------------------ */
311    /* -------------------- address conversion -------------------- */
312    /* ------------------------------------------------------------ */
313
314    /* We divide the memory blocks we allocate into two "chunks", the
315     * "prolog chunk" where we store information about the allocation,
316     * and the "user chunk" which we return to the caller to use.
317     */
318
319    /* ---------------------------------------- alignment */
320
321    const size_t ALIGNMENT = 4;
322
323    /* If "value" (a memory size or offset) falls on an alignment boundary,
324     * then just return it.  Otherwise return the smallest number larger
325     * than "value" that falls on an alignment boundary.
326     */   
327
328    #define PAD_TO_ALIGNMENT_BOUNDARY(value) \
329        ((value) + ((ALIGNMENT - ((value) % ALIGNMENT)) % ALIGNMENT))
330
331    /* ---------------------------------------- chunk structs */
332   
333    /* We declare incomplete structures for each chunk, just to
334     * provide type safety.
335     */
336
337    struct PrologChunk;
338    struct UserChunk;
339
340    /* ---------------------------------------- chunk sizes and offsets */
341
342    const size_t SIZE_BlockHeader = PAD_TO_ALIGNMENT_BOUNDARY(sizeof(BlockHeader));
343    const size_t SIZE_Signature = PAD_TO_ALIGNMENT_BOUNDARY(sizeof(Signature));
344
345    const size_t OFFSET_BlockHeader = 0;
346    const size_t OFFSET_Signature = OFFSET_BlockHeader + SIZE_BlockHeader;
347    const size_t OFFSET_UserChunk = OFFSET_Signature + SIZE_Signature;
348   
349    const size_t SIZE_PrologChunk = OFFSET_UserChunk;
350
351    /* ---------------------------------------- GetUserAddress */
352
353    static UserChunk *GetUserAddress(PrologChunk *pProlog)
354    {
355        char *pchProlog = reinterpret_cast<char *>(pProlog);
356        char *pchUser = pchProlog + OFFSET_UserChunk;
357        UserChunk *pUser = reinterpret_cast<UserChunk *>(pchUser);
358        return pUser;
359    }
360
361    /* ---------------------------------------- GetPrologAddress */
362
363    static PrologChunk *GetPrologAddress(UserChunk *pUser)
364    {
365        char *pchUser = reinterpret_cast<char *>(pUser);
366        char *pchProlog = pchUser - OFFSET_UserChunk;
367        PrologChunk *pProlog = reinterpret_cast<PrologChunk *>(pchProlog);
368        return pProlog;
369    }
370
371    /* ---------------------------------------- GetHeaderAddress */
372
373    static BlockHeader *GetHeaderAddress(PrologChunk *pProlog)
374    {
375        char *pchProlog = reinterpret_cast<char *>(pProlog);
376        char *pchHeader = pchProlog + OFFSET_BlockHeader;
377        BlockHeader *pHeader = reinterpret_cast<BlockHeader *>(pchHeader);
378        return pHeader;
379    }
380
381    /* ---------------------------------------- GetSignatureAddress */
382
383    static Signature *GetSignatureAddress(PrologChunk *pProlog)
384    {
385        char *pchProlog = reinterpret_cast<char *>(pProlog);
386        char *pchSignature = pchProlog + OFFSET_Signature;
387        Signature *pSignature = reinterpret_cast<Signature *>(pchSignature);
388        return pSignature;
389    }
390
391    /* ------------------------------------------------------------ */
392    /* -------------- memory allocation and stamping -------------- */
393    /* ------------------------------------------------------------ */
394
395    /* ---------------------------------------- TrackMalloc */
396   
397    void *TrackMalloc(size_t size)
398    {
399        // Allocate the memory, including space for the prolog.
400        PrologChunk *pProlog = (PrologChunk *)malloc(SIZE_PrologChunk + size);
401       
402        // If the allocation failed, then return NULL.
403        if (pProlog == NULL) return NULL;
404       
405        // Use placement new to construct the block header in place.
406        BlockHeader *pBlockHeader = new (pProlog) BlockHeader(size);
407       
408        // Link the block header into the list of extant block headers.
409        BlockHeader::AddNode(pBlockHeader);
410       
411        // Use placement new to construct the signature in place.
412        Signature *pSignature = new (GetSignatureAddress(pProlog)) Signature;
413       
414        // Get the offset to the user chunk and return it.
415        UserChunk *pUser = GetUserAddress(pProlog);
416
417        currentMemorySize += size ;
418        if (currentMemorySize>maxMemorySize) maxMemorySize=currentMemorySize ;
419       
420        return pUser;
421    }
422
423    /* ---------------------------------------- TrackFree */
424   
425    void TrackFree(void *p)
426    {
427        // It's perfectly valid for "p" to be null; return if it is.
428        if (p == NULL) return;
429   
430        // Get the prolog address for this memory block.
431        UserChunk *pUser = reinterpret_cast<UserChunk *>(p);   
432        PrologChunk *pProlog = GetPrologAddress(pUser);
433       
434        // Check the signature, and if it's invalid, return immediately.
435        Signature *pSignature = GetSignatureAddress(pProlog);
436        if (!Signature::IsValidSignature(pSignature)) return;
437       
438        // Destroy the signature.
439        pSignature->~Signature();
440        pSignature = NULL;
441
442        // Unlink the block header from the list and destroy it.
443        BlockHeader *pBlockHeader = GetHeaderAddress(pProlog);
444        currentMemorySize-=pBlockHeader->GetRequestedSize();
445        BlockHeader::RemoveNode(pBlockHeader);
446        pBlockHeader->~BlockHeader();
447        pBlockHeader = NULL;
448
449        // Free the memory block.   
450        free(pProlog);
451    }
452
453    /* ---------------------------------------- TrackStamp */
454
455    void TrackStamp(void *p, const MemStamp &stamp, char const *typeName)
456    {
457        // Get the header and signature address for this pointer.
458        UserChunk *pUser = reinterpret_cast<UserChunk *>(p);
459        PrologChunk *pProlog = GetPrologAddress(pUser);
460        BlockHeader *pHeader = GetHeaderAddress(pProlog);
461        Signature *pSignature = GetSignatureAddress(pProlog);
462
463        // If the signature is not valid, then return immediately.
464        if (!Signature::IsValidSignature(pSignature)) return;
465
466        // "Stamp" the information onto the header.
467        pHeader->Stamp(stamp.filename, stamp.lineNum, typeName);
468    }
469
470    /* ---------------------------------------- TrackDumpBlocks */
471
472    void TrackDumpBlocks(std::ofstream& memReport, size_t memtrack_blocks, size_t memtrack_size )
473    {
474        // Get an array of pointers to all extant blocks.
475        std::ostringstream ostr ;
476        size_t numBlocks = BlockHeader::CountBlocks();
477        BlockHeader **ppBlockHeader =
478            (BlockHeader **)calloc(numBlocks, sizeof(*ppBlockHeader));
479        BlockHeader::GetBlocks(ppBlockHeader);
480        // Dump information about the memory blocks.
481       
482        memReport<<std::endl;
483        memReport<<"=====================" <<std::endl ;
484        memReport<<"Current Memory Blocks" <<std::endl ;
485        memReport<<"=====================" <<std::endl ;
486        memReport<<std::endl ;
487        char strbuff[10000] ;
488        std::multimap<size_t,BlockHeader *,std::greater<int>> orderedBlocks ;
489        for (size_t i = 0; i < numBlocks; i++)
490        {
491          BlockHeader *pBlockHeader = ppBlockHeader[i];
492          size_t size = pBlockHeader->GetRequestedSize();
493          orderedBlocks.insert({size,pBlockHeader}) ;
494        }
495       
496        xios::CAddr2line myaddr2line ;
497        size_t i = 0 ;
498        for(auto& it : orderedBlocks)
499        {
500            BlockHeader *pBlockHeader = it.second ;
501            char const *typeName = pBlockHeader->GetTypeName();
502            size_t size = pBlockHeader->GetRequestedSize();
503            char const *fileName = pBlockHeader->GetFilename();
504            int lineNum = pBlockHeader->GetLineNum();
505            if (memtrack_blocks>0 && i>memtrack_blocks) break ;           
506            if (memtrack_size>0 && size<memtrack_size) break ;           
507           
508            sprintf(strbuff,"*** #%-6d %5d bytes %-50s\n", i, size, typeName);
509            memReport<<strbuff ;
510            sprintf(strbuff,"... %s:%d\n", fileName, lineNum);
511            memReport<<strbuff ;
512            //pBlockHeader->backTrace(memReport, myaddr2line);
513            pBlockHeader->backTrace(memReport);
514            i++ ;
515        }
516        // Clean up.
517        free(ppBlockHeader);
518    }
519
520    /* ---------------------------------------- struct MemDigest */
521
522    struct MemDigest
523    {
524        char const *typeName;
525        int blockCount;
526        size_t totalSize;
527
528        static bool TotalSizeGreaterThan(const MemDigest &md1, const MemDigest &md2)
529            { return md1.totalSize > md2.totalSize; }
530    };
531
532
533    /* ---------------------------------------- SummarizeMemoryUsageForType */
534
535    static void SummarizeMemoryUsageForType(
536        MemDigest *pMemDigest,
537        BlockHeader **ppBlockHeader,
538        size_t startPost,
539        size_t endPost
540    )
541    {
542        pMemDigest->typeName = ppBlockHeader[startPost]->GetTypeName();
543        pMemDigest->blockCount = 0;
544        pMemDigest->totalSize = 0;
545        for (size_t i = startPost; i < endPost; i++)
546        {
547            pMemDigest->blockCount++;
548            pMemDigest->totalSize += ppBlockHeader[i]->GetRequestedSize();
549            assert(strcmp(ppBlockHeader[i]->GetTypeName(), pMemDigest->typeName) == 0);
550        }
551    }
552
553    /* ---------------------------------------- TrackListMemoryUsage */
554
555    void TrackListMemoryUsage()
556    {
557        // If there are no allocated blocks, then return now.
558        size_t numBlocks = BlockHeader::CountBlocks();
559        if (numBlocks == 0) return;
560
561        // Get an array of pointers to all extant blocks.
562        BlockHeader **ppBlockHeader =
563            (BlockHeader **)calloc(numBlocks, sizeof(*ppBlockHeader));
564        BlockHeader::GetBlocks(ppBlockHeader);
565
566        // Sort the blocks by type name.
567        std::sort(
568            ppBlockHeader,
569            ppBlockHeader + numBlocks,
570            BlockHeader::TypeGreaterThan
571        );
572
573        // Find out how many unique types we have.
574        size_t numUniqueTypes = 1;
575        for (size_t i = 1; i < numBlocks; i++)
576        {
577            char const *prevTypeName = ppBlockHeader[i - 1]->GetTypeName();
578            char const *currTypeName = ppBlockHeader[i]->GetTypeName();
579            if (strcmp(prevTypeName, currTypeName) != 0) numUniqueTypes++;
580        }
581
582        // Create an array of "digests" summarizing memory usage by type.
583        size_t startPost = 0;
584        size_t uniqueTypeIndex = 0;
585        MemDigest *pMemDigestArray =
586            (MemDigest *)calloc(numUniqueTypes, sizeof(*pMemDigestArray));
587        for (size_t i = 1; i <= numBlocks; i++)    // yes, less than or *equal* to
588        {
589            char const *prevTypeName = ppBlockHeader[i - 1]->GetTypeName();
590            char const *currTypeName = (i < numBlocks) ? ppBlockHeader[i]->GetTypeName() : "";
591            if (strcmp(prevTypeName, currTypeName) != 0)
592            {
593                size_t endPost = i;
594                SummarizeMemoryUsageForType(
595                    pMemDigestArray + uniqueTypeIndex,
596                    ppBlockHeader,
597                    startPost,
598                    endPost
599                );
600                startPost = endPost;
601                uniqueTypeIndex++;
602            }
603        }
604        assert(uniqueTypeIndex = numUniqueTypes);
605
606        // Sort the digests by total memory usage.
607        std::sort(
608            pMemDigestArray,
609            pMemDigestArray + numUniqueTypes,
610            MemDigest::TotalSizeGreaterThan
611        );
612
613        // Compute the grand total memory usage.
614        size_t grandTotalNumBlocks = 0;
615        size_t grandTotalSize = 0;
616        for (size_t i = 0; i < numUniqueTypes; i++)
617        {
618            grandTotalNumBlocks += pMemDigestArray[i].blockCount;
619            grandTotalSize += pMemDigestArray[i].totalSize;
620        }
621
622        // Dump the memory usage statistics.
623        printf("\n");
624        printf("-----------------------\n");
625        printf("Memory Usage Statistics\n");
626        printf("-----------------------\n");
627        printf("\n");
628        printf("%-50s%5s  %5s %7s %s \n", "allocated type", "blocks", "", "bytes", "");
629        printf("%-50s%5s  %5s %7s %s \n", "--------------", "------", "", "-----", "");
630
631        for (size_t i = 0; i < numUniqueTypes; i++)
632        {
633            MemDigest *pMD = pMemDigestArray + i;
634            size_t blockCount = pMD->blockCount;
635            double blockCountPct = 100.0 * blockCount / grandTotalNumBlocks;
636            size_t totalSize = pMD->totalSize;
637            double totalSizePct = 100.0 * totalSize / grandTotalSize;
638
639            printf(
640                "%-50s %5d %5.1f%% %7d %5.1f%%\n",
641                pMD->typeName,
642                blockCount,
643                blockCountPct,
644                totalSize,
645                totalSizePct
646            );
647        }
648        printf("%-50s %5s %5s  %7s %s \n", "--------", "-----", "", "-------", "");
649        printf("%-50s %5d %5s  %7d %s \n", "[totals]", grandTotalNumBlocks, "", grandTotalSize, "");
650
651        // Clean up.
652        free(ppBlockHeader);
653        free(pMemDigestArray);
654    }
655
656}    // namespace MemTrack
657
658/* ------------------------------------------------------------ */
659/* ---------------------- new and delete ---------------------- */
660/* ------------------------------------------------------------ */
661
662/* ---------------------------------------- operator new */
663
664void *operator new(size_t size)
665{
666    void *p = MemTrack::TrackMalloc(size);
667    if (p == NULL) throw std::bad_alloc();
668    return p;
669}
670
671/* ---------------------------------------- operator delete */
672
673void operator delete(void *p)
674{
675    MemTrack::TrackFree(p);
676}
677
678/* ---------------------------------------- operator new[] */
679
680void *operator new[](size_t size)
681{
682    void *p = MemTrack::TrackMalloc(size);
683    if (p == NULL) throw std::bad_alloc();
684    return p;
685}
686
687/* ---------------------------------------- operator delete[] */
688
689void operator delete[](void *p)
690{
691    MemTrack::TrackFree(p);
692}
693
694#endif
Note: See TracBrowser for help on using the repository browser.