source: XIOS/dev/XIOS_DEV_CMIP6/src/memtrack.cpp @ 1251

Last change on this file since 1251 was 1158, checked in by oabramkina, 7 years ago

Two server levels: merging with trunk r1137.
There are bugs.

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