source: XIOS/dev/branch_yushan/src/memtrack.cpp @ 1095

Last change on this file since 1095 was 1095, checked in by yushan, 7 years ago

modif for Curie, CurrContext?->CurrContext_ptr in object_factory and group_factory

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