source: XIOS/dev/branch_yushan_merged/src/memtrack.cpp @ 1205

Last change on this file since 1205 was 1205, checked in by yushan, 4 years ago

branch merged with trunk @1200

  • 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: 21.6 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
48#include "memtrack.hpp"
49#undef new    // IMPORTANT!
50
51extern "C"
52{
53  void addr2line(const char *file_name, char** addr, int naddr) ;
54#ifdef XIOS_MEMTRACK_LIGHT
55  void addr2line(const char *file_name, char** addr, int naddr) {} 
56#endif
57}
58/* ------------------------------------------------------------ */
59/* -------------------- namespace MemTrack -------------------- */
60/* ------------------------------------------------------------ */
61
62namespace MemTrack
63{
64    size_t currentMemorySize=0 ;
65    size_t maxMemorySize=0 ; 
66
67    size_t getCurrentMemorySize(void) {return currentMemorySize; }
68    size_t getMaxMemorySize(void) {return maxMemorySize ; }
69
70    /* ------------------------------------------------------------ */
71    /* --------------------- class BlockHeader -------------------- */
72    /* ------------------------------------------------------------ */
73
74    class BlockHeader
75    {
76        private:    // static member variables
77            static BlockHeader *ourFirstNode;
78            #pragma omp threadprivate(ourFirstNode)
79   
80        private:    // member variables
81            BlockHeader *myPrevNode;
82            BlockHeader *myNextNode;
83            size_t myRequestedSize;
84            char const *myFilename;
85            int myLineNum;
86            char const *myTypeName;
87           
88            size_t stackSize ;
89            void* stackArray[20] ;
90
91        public:     // members
92            BlockHeader(size_t requestedSize);
93            ~BlockHeader();
94       
95            size_t GetRequestedSize() const { return myRequestedSize; }
96            char const *GetFilename() const { return myFilename; }
97            int GetLineNum() const { return myLineNum; }
98            char const *GetTypeName() const { return myTypeName; }
99       
100            void Stamp(char const *filename, int lineNum, char const *typeName);
101            void backTrace(void) ;
102       
103            static void AddNode(BlockHeader *node);
104            static void RemoveNode(BlockHeader *node);
105            static size_t CountBlocks();
106            static void GetBlocks(BlockHeader **blockHeaderPP);
107            static bool TypeGreaterThan(BlockHeader *header1, BlockHeader *header2);
108    };
109
110    /* ---------------------------------------- BlockHeader static member variables */
111
112    BlockHeader *BlockHeader::ourFirstNode = NULL;
113
114    /* ---------------------------------------- BlockHeader constructor */
115
116    BlockHeader::BlockHeader(size_t requestedSize)
117    {
118        myPrevNode = NULL;
119        myNextNode = NULL;
120        myRequestedSize = requestedSize;
121        myFilename = "[unknown]";
122        myLineNum = 0;
123        myTypeName = "[unknown]";
124        stackSize=backtrace(stackArray,20) ;
125    }
126
127    /* ---------------------------------------- BlockHeader destructor */
128
129    BlockHeader::~BlockHeader()
130    {
131    }
132       
133    /* ---------------------------------------- BlockHeader Stamp */
134
135    void BlockHeader::Stamp(char const *filename, int lineNum, char const *typeName)
136    {
137        myFilename = filename;
138        myLineNum = lineNum;
139        myTypeName = typeName;
140    }
141
142    void BlockHeader::backTrace(void)
143    {   
144       
145//        oss<<"addr2line -C -f -i -s -e ../bin/test_client.exe " ;
146        char *addr ;
147        char buffer[20] ;
148        addr=buffer ;
149        for(int i=0;i<stackSize;i++) 
150        {
151          std::ostringstream oss ;
152          oss<<stackArray[i] ;
153          strcpy(addr,oss.str().c_str()) ;
154          addr2line("/proc/self/exe",&addr,1) ;
155        }
156    }
157    /* ---------------------------------------- BlockHeader AddNode */
158
159    void BlockHeader::AddNode(BlockHeader *node)
160    {
161        assert(node != NULL);
162        assert(node->myPrevNode == NULL);
163        assert(node->myNextNode == NULL);
164
165        // If we have at least one node in the list ...       
166        if (ourFirstNode != NULL)
167        {
168            // ... make the new node the first node's predecessor.
169            assert(ourFirstNode->myPrevNode == NULL);
170            ourFirstNode->myPrevNode = node;
171        }
172
173        // Make the first node the new node's succesor.
174        node->myNextNode = ourFirstNode;
175
176        // Make the new node the first node.
177        ourFirstNode = node;
178    }
179
180    /* ---------------------------------------- BlockHeader RemoveNode */
181
182    void BlockHeader::RemoveNode(BlockHeader *node)
183    {
184        assert(node != NULL);
185        assert(ourFirstNode != NULL);
186
187        // If target node is the first node in the list...
188        if (ourFirstNode == node)
189        {
190            // ... make the target node's successor the first node.
191            assert(ourFirstNode->myPrevNode == NULL);
192            ourFirstNode = node->myNextNode;
193        }
194       
195        // Link target node's predecessor, if any, to its successor.
196        if (node->myPrevNode != NULL)
197        {
198            node->myPrevNode->myNextNode = node->myNextNode;
199        }
200       
201        // Link target node's successor, if any, to its predecessor.
202        if (node->myNextNode != NULL)
203        {
204            node->myNextNode->myPrevNode = node->myPrevNode;
205        }
206
207        // Clear target node's previous and next pointers.
208        node->myPrevNode = NULL;
209        node->myNextNode = NULL;
210    }
211
212    /* ---------------------------------------- BlockHeader CountBlocks */
213
214    size_t BlockHeader::CountBlocks()
215    {
216        size_t count = 0;
217        BlockHeader *currNode = ourFirstNode;
218        while (currNode != NULL)
219        {
220            count++;
221            currNode = currNode->myNextNode;
222        }
223        return count;
224    }
225
226    /* ---------------------------------------- BlockHeader GetBlocks */
227
228    void BlockHeader::GetBlocks(BlockHeader **blockHeaderPP)
229    {
230        BlockHeader *currNode = ourFirstNode;
231        while (currNode != NULL)
232        {
233            *blockHeaderPP = currNode;
234            blockHeaderPP++;
235            currNode = currNode->myNextNode;
236        }
237    }
238
239    /* ---------------------------------------- BlockHeader TypeGreaterThan */
240
241    bool BlockHeader::TypeGreaterThan(BlockHeader *header1, BlockHeader *header2)
242    {
243        return (strcmp(header1->myTypeName, header2->myTypeName) > 0);
244    }
245
246    /* ------------------------------------------------------------ */
247    /* ---------------------- class Signature --------------------- */
248    /* ------------------------------------------------------------ */
249
250    class Signature
251    {
252        private:    // constants
253            static const unsigned int SIGNATURE1 = 0xCAFEBABE;
254            static const unsigned int SIGNATURE2 = 0xFACEFACE;
255       
256        private:    // member variables
257            unsigned int mySignature1;
258            unsigned int mySignature2;
259           
260        public:        // construction/destruction
261            Signature() : mySignature1(SIGNATURE1), mySignature2(SIGNATURE2) {};
262            ~Signature() { mySignature1 = 0; mySignature2 = 0; }
263           
264        public:        // static member functions
265            static bool IsValidSignature(const Signature *pProspectiveSignature)
266            {
267                try
268                {
269                    if (pProspectiveSignature->mySignature1 != SIGNATURE1) return false;
270                    if (pProspectiveSignature->mySignature2 != SIGNATURE2) return false;
271                    return true;
272                }
273                catch (...)
274                {
275                    return false;
276                }
277            }
278    };
279
280    /* ------------------------------------------------------------ */
281    /* -------------------- address conversion -------------------- */
282    /* ------------------------------------------------------------ */
283
284    /* We divide the memory blocks we allocate into two "chunks", the
285     * "prolog chunk" where we store information about the allocation,
286     * and the "user chunk" which we return to the caller to use.
287     */
288
289    /* ---------------------------------------- alignment */
290
291    const size_t ALIGNMENT = 4;
292
293    /* If "value" (a memory size or offset) falls on an alignment boundary,
294     * then just return it.  Otherwise return the smallest number larger
295     * than "value" that falls on an alignment boundary.
296     */   
297
298    #define PAD_TO_ALIGNMENT_BOUNDARY(value) \
299        ((value) + ((ALIGNMENT - ((value) % ALIGNMENT)) % ALIGNMENT))
300
301    /* ---------------------------------------- chunk structs */
302   
303    /* We declare incomplete structures for each chunk, just to
304     * provide type safety.
305     */
306
307    struct PrologChunk;
308    struct UserChunk;
309
310    /* ---------------------------------------- chunk sizes and offsets */
311
312    const size_t SIZE_BlockHeader = PAD_TO_ALIGNMENT_BOUNDARY(sizeof(BlockHeader));
313    const size_t SIZE_Signature = PAD_TO_ALIGNMENT_BOUNDARY(sizeof(Signature));
314
315    const size_t OFFSET_BlockHeader = 0;
316    const size_t OFFSET_Signature = OFFSET_BlockHeader + SIZE_BlockHeader;
317    const size_t OFFSET_UserChunk = OFFSET_Signature + SIZE_Signature;
318   
319    const size_t SIZE_PrologChunk = OFFSET_UserChunk;
320
321    /* ---------------------------------------- GetUserAddress */
322
323    static UserChunk *GetUserAddress(PrologChunk *pProlog)
324    {
325        char *pchProlog = reinterpret_cast<char *>(pProlog);
326        char *pchUser = pchProlog + OFFSET_UserChunk;
327        UserChunk *pUser = reinterpret_cast<UserChunk *>(pchUser);
328        return pUser;
329    }
330
331    /* ---------------------------------------- GetPrologAddress */
332
333    static PrologChunk *GetPrologAddress(UserChunk *pUser)
334    {
335        char *pchUser = reinterpret_cast<char *>(pUser);
336        char *pchProlog = pchUser - OFFSET_UserChunk;
337        PrologChunk *pProlog = reinterpret_cast<PrologChunk *>(pchProlog);
338        return pProlog;
339    }
340
341    /* ---------------------------------------- GetHeaderAddress */
342
343    static BlockHeader *GetHeaderAddress(PrologChunk *pProlog)
344    {
345        char *pchProlog = reinterpret_cast<char *>(pProlog);
346        char *pchHeader = pchProlog + OFFSET_BlockHeader;
347        BlockHeader *pHeader = reinterpret_cast<BlockHeader *>(pchHeader);
348        return pHeader;
349    }
350
351    /* ---------------------------------------- GetSignatureAddress */
352
353    static Signature *GetSignatureAddress(PrologChunk *pProlog)
354    {
355        char *pchProlog = reinterpret_cast<char *>(pProlog);
356        char *pchSignature = pchProlog + OFFSET_Signature;
357        Signature *pSignature = reinterpret_cast<Signature *>(pchSignature);
358        return pSignature;
359    }
360
361    /* ------------------------------------------------------------ */
362    /* -------------- memory allocation and stamping -------------- */
363    /* ------------------------------------------------------------ */
364
365    /* ---------------------------------------- TrackMalloc */
366   
367    void *TrackMalloc(size_t size)
368    {
369        // Allocate the memory, including space for the prolog.
370        PrologChunk *pProlog = (PrologChunk *)malloc(SIZE_PrologChunk + size);
371       
372        // If the allocation failed, then return NULL.
373        if (pProlog == NULL) return NULL;
374       
375        // Use placement new to construct the block header in place.
376        BlockHeader *pBlockHeader = new (pProlog) BlockHeader(size);
377       
378        // Link the block header into the list of extant block headers.
379        BlockHeader::AddNode(pBlockHeader);
380       
381        // Use placement new to construct the signature in place.
382        Signature *pSignature = new (GetSignatureAddress(pProlog)) Signature;
383       
384        // Get the offset to the user chunk and return it.
385        UserChunk *pUser = GetUserAddress(pProlog);
386
387        currentMemorySize += size ;
388        if (currentMemorySize>maxMemorySize) maxMemorySize=currentMemorySize ;
389       
390        return pUser;
391    }
392
393    /* ---------------------------------------- TrackFree */
394   
395    void TrackFree(void *p)
396    {
397        // It's perfectly valid for "p" to be null; return if it is.
398        if (p == NULL) return;
399   
400        // Get the prolog address for this memory block.
401        UserChunk *pUser = reinterpret_cast<UserChunk *>(p);   
402        PrologChunk *pProlog = GetPrologAddress(pUser);
403       
404        // Check the signature, and if it's invalid, return immediately.
405        Signature *pSignature = GetSignatureAddress(pProlog);
406        if (!Signature::IsValidSignature(pSignature)) return;
407       
408        // Destroy the signature.
409        pSignature->~Signature();
410        pSignature = NULL;
411
412        // Unlink the block header from the list and destroy it.
413        BlockHeader *pBlockHeader = GetHeaderAddress(pProlog);
414        currentMemorySize-=pBlockHeader->GetRequestedSize();
415        BlockHeader::RemoveNode(pBlockHeader);
416        pBlockHeader->~BlockHeader();
417        pBlockHeader = NULL;
418
419        // Free the memory block.   
420        free(pProlog);
421    }
422
423    /* ---------------------------------------- TrackStamp */
424
425    void TrackStamp(void *p, const MemStamp &stamp, char const *typeName)
426    {
427        // Get the header and signature address for this pointer.
428        UserChunk *pUser = reinterpret_cast<UserChunk *>(p);
429        PrologChunk *pProlog = GetPrologAddress(pUser);
430        BlockHeader *pHeader = GetHeaderAddress(pProlog);
431        Signature *pSignature = GetSignatureAddress(pProlog);
432
433        // If the signature is not valid, then return immediately.
434        if (!Signature::IsValidSignature(pSignature)) return;
435
436        // "Stamp" the information onto the header.
437        pHeader->Stamp(stamp.filename, stamp.lineNum, typeName);
438    }
439
440    /* ---------------------------------------- TrackDumpBlocks */
441
442    void TrackDumpBlocks()
443    {
444        // Get an array of pointers to all extant blocks.
445        size_t numBlocks = BlockHeader::CountBlocks();
446        BlockHeader **ppBlockHeader =
447            (BlockHeader **)calloc(numBlocks, sizeof(*ppBlockHeader));
448        BlockHeader::GetBlocks(ppBlockHeader);
449
450        // Dump information about the memory blocks.
451        printf("\n");
452        printf("=====================\n");
453        printf("Current Memory Blocks\n");
454        printf("=====================\n");
455        printf("\n");
456        for (size_t i = 0; i < numBlocks; i++)
457        {
458            BlockHeader *pBlockHeader = ppBlockHeader[i];
459            char const *typeName = pBlockHeader->GetTypeName();
460            size_t size = pBlockHeader->GetRequestedSize();
461            char const *fileName = pBlockHeader->GetFilename();
462            int lineNum = pBlockHeader->GetLineNum();
463            printf("*** #%-6d %5d bytes %-50s\n", i, size, typeName);
464            printf("... %s:%d\n", fileName, lineNum);
465            pBlockHeader->backTrace();
466        }
467
468        // Clean up.
469        free(ppBlockHeader);
470    }
471
472    /* ---------------------------------------- struct MemDigest */
473
474    struct MemDigest
475    {
476        char const *typeName;
477        int blockCount;
478        size_t totalSize;
479
480        static bool TotalSizeGreaterThan(const MemDigest &md1, const MemDigest &md2)
481            { return md1.totalSize > md2.totalSize; }
482    };
483
484
485    /* ---------------------------------------- SummarizeMemoryUsageForType */
486
487    static void SummarizeMemoryUsageForType(
488        MemDigest *pMemDigest,
489        BlockHeader **ppBlockHeader,
490        size_t startPost,
491        size_t endPost
492    )
493    {
494        pMemDigest->typeName = ppBlockHeader[startPost]->GetTypeName();
495        pMemDigest->blockCount = 0;
496        pMemDigest->totalSize = 0;
497        for (size_t i = startPost; i < endPost; i++)
498        {
499            pMemDigest->blockCount++;
500            pMemDigest->totalSize += ppBlockHeader[i]->GetRequestedSize();
501            assert(strcmp(ppBlockHeader[i]->GetTypeName(), pMemDigest->typeName) == 0);
502        }
503    }
504
505    /* ---------------------------------------- TrackListMemoryUsage */
506
507    void TrackListMemoryUsage()
508    {
509        // If there are no allocated blocks, then return now.
510        size_t numBlocks = BlockHeader::CountBlocks();
511        if (numBlocks == 0) return;
512
513        // Get an array of pointers to all extant blocks.
514        BlockHeader **ppBlockHeader =
515            (BlockHeader **)calloc(numBlocks, sizeof(*ppBlockHeader));
516        BlockHeader::GetBlocks(ppBlockHeader);
517
518        // Sort the blocks by type name.
519        std::sort(
520            ppBlockHeader,
521            ppBlockHeader + numBlocks,
522            BlockHeader::TypeGreaterThan
523        );
524
525        // Find out how many unique types we have.
526        size_t numUniqueTypes = 1;
527        for (size_t i = 1; i < numBlocks; i++)
528        {
529            char const *prevTypeName = ppBlockHeader[i - 1]->GetTypeName();
530            char const *currTypeName = ppBlockHeader[i]->GetTypeName();
531            if (strcmp(prevTypeName, currTypeName) != 0) numUniqueTypes++;
532        }
533
534        // Create an array of "digests" summarizing memory usage by type.
535        size_t startPost = 0;
536        size_t uniqueTypeIndex = 0;
537        MemDigest *pMemDigestArray =
538            (MemDigest *)calloc(numUniqueTypes, sizeof(*pMemDigestArray));
539        for (size_t i = 1; i <= numBlocks; i++)    // yes, less than or *equal* to
540        {
541            char const *prevTypeName = ppBlockHeader[i - 1]->GetTypeName();
542            char const *currTypeName = (i < numBlocks) ? ppBlockHeader[i]->GetTypeName() : "";
543            if (strcmp(prevTypeName, currTypeName) != 0)
544            {
545                size_t endPost = i;
546                SummarizeMemoryUsageForType(
547                    pMemDigestArray + uniqueTypeIndex,
548                    ppBlockHeader,
549                    startPost,
550                    endPost
551                );
552                startPost = endPost;
553                uniqueTypeIndex++;
554            }
555        }
556        assert(uniqueTypeIndex = numUniqueTypes);
557
558        // Sort the digests by total memory usage.
559        std::sort(
560            pMemDigestArray,
561            pMemDigestArray + numUniqueTypes,
562            MemDigest::TotalSizeGreaterThan
563        );
564
565        // Compute the grand total memory usage.
566        size_t grandTotalNumBlocks = 0;
567        size_t grandTotalSize = 0;
568        for (size_t i = 0; i < numUniqueTypes; i++)
569        {
570            grandTotalNumBlocks += pMemDigestArray[i].blockCount;
571            grandTotalSize += pMemDigestArray[i].totalSize;
572        }
573
574        // Dump the memory usage statistics.
575        printf("\n");
576        printf("-----------------------\n");
577        printf("Memory Usage Statistics\n");
578        printf("-----------------------\n");
579        printf("\n");
580        printf("%-50s%5s  %5s %7s %s \n", "allocated type", "blocks", "", "bytes", "");
581        printf("%-50s%5s  %5s %7s %s \n", "--------------", "------", "", "-----", "");
582
583        for (size_t i = 0; i < numUniqueTypes; i++)
584        {
585            MemDigest *pMD = pMemDigestArray + i;
586            size_t blockCount = pMD->blockCount;
587            double blockCountPct = 100.0 * blockCount / grandTotalNumBlocks;
588            size_t totalSize = pMD->totalSize;
589            double totalSizePct = 100.0 * totalSize / grandTotalSize;
590
591            printf(
592                "%-50s %5d %5.1f%% %7d %5.1f%%\n",
593                pMD->typeName,
594                blockCount,
595                blockCountPct,
596                totalSize,
597                totalSizePct
598            );
599        }
600        printf("%-50s %5s %5s  %7s %s \n", "--------", "-----", "", "-------", "");
601        printf("%-50s %5d %5s  %7d %s \n", "[totals]", grandTotalNumBlocks, "", grandTotalSize, "");
602
603        // Clean up.
604        free(ppBlockHeader);
605        free(pMemDigestArray);
606    }
607
608}    // namespace MemTrack
609
610/* ------------------------------------------------------------ */
611/* ---------------------- new and delete ---------------------- */
612/* ------------------------------------------------------------ */
613
614/* ---------------------------------------- operator new */
615
616void *operator new(size_t size)
617{
618    void *p = MemTrack::TrackMalloc(size);
619    if (p == NULL) throw std::bad_alloc();
620    return p;
621}
622
623/* ---------------------------------------- operator delete */
624
625void operator delete(void *p)
626{
627    MemTrack::TrackFree(p);
628}
629
630/* ---------------------------------------- operator new[] */
631
632void *operator new[](size_t size)
633{
634    void *p = MemTrack::TrackMalloc(size);
635    if (p == NULL) throw std::bad_alloc();
636    return p;
637}
638
639/* ---------------------------------------- operator delete[] */
640
641void operator delete[](void *p)
642{
643    MemTrack::TrackFree(p);
644}
645
646#endif
Note: See TracBrowser for help on using the repository browser.