source: src/Common/Stats/Heap.cc @ 1756e08

ADTast-experimental
Last change on this file since 1756e08 was c15085d, checked in by Fangren Yu <f37yu@…>, 4 years ago

tracing memory allocation of resolver passes

  • Property mode set to 100644
File size: 8.1 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Heap.cc --
8//
9// Author           : Thierry Delisle
10// Created On       : Thu May  3 16:16:10 2018
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri May  4 17:27:31 2018
13// Update Count     : 28
14//
15
16#include <cassert>
17#include <cmath>
18#include <cstddef>
19#include <cstring>
20#include <iomanip>
21#include <iostream>
22
23#if defined(__has_feature)
24        #if __has_feature(address_sanitizer)
25                #define NO_HEAP_STATISTICS
26        # endif
27#endif
28
29#if defined( NO_STATISTICS ) || defined( TCMALLOC ) || defined(__SANITIZE_ADDRESS__)
30        #if !defined(NO_HEAP_STATISTICS)
31                #define NO_HEAP_STATISTICS
32        #endif
33#endif
34
35namespace Stats {
36        namespace Heap {
37#if defined( NO_HEAP_STATISTICS )
38                void newPass( const char * const ) {}
39
40                void print() {}
41#else
42                extern bool enabled;
43
44                struct StatBlock {
45                        const char * name  = nullptr;   ///< Name of this pass
46                        size_t mallocs     = 0;                 ///< Allocations in this pass
47                        size_t frees       = 0;                 ///< Frees in this pass
48                        size_t n_allocs    = 0;                 ///< Current number of live allocations
49                        size_t peak_allocs = 0;                 ///< Peak number of live allocations this pass
50                };
51
52                StatBlock    passes[100] = {{ "Pre-Parse", 0, 0, 0, 0 }};
53                const size_t passes_size = sizeof(passes) / sizeof(passes[0]);
54                size_t       passes_cnt = 1;
55
56                StatBlock    stacktrace_stats[100];
57                size_t       stacktrace_stats_count = 0;
58                bool         stacktrace_stats_enabled = true;
59
60                size_t       trace[1000];
61                const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t);
62                size_t       stacktrace_depth;
63
64                size_t new_stacktrace_id(const char * const name) {
65                        stacktrace_stats[stacktrace_stats_count].name = name;
66                        return stacktrace_stats_count++;
67                }
68
69                void stacktrace_push(size_t id) {
70                        ++stacktrace_depth;
71                        assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc");
72                        trace[stacktrace_depth] = id;
73                }
74
75                void stacktrace_pop() {
76                        assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty");
77                        --stacktrace_depth;
78                }
79
80                void newPass( const char * const name ) {
81                        passes[passes_cnt].name    = name;
82                        passes[passes_cnt].mallocs = 0;
83                        passes[passes_cnt].frees   = 0;
84                        passes[passes_cnt].n_allocs
85                                = passes[passes_cnt].peak_allocs
86                                = passes[passes_cnt-1].n_allocs;
87                        passes_cnt++;
88
89                        assertf(passes_cnt < passes_size, "Too many passes for Stats::Heap, increase the size of the array in Heap.cc");
90                }
91
92                void print(size_t value, size_t total) {
93                        std::cerr << std::setw(12) << value;
94                        std::cerr << "(" << std::setw(3);
95                        std::cerr << (value == 0 ? 0 : value * 100 / total);
96                        std::cerr << "%) | ";
97                }
98
99                void print(const StatBlock& stat, size_t nc, size_t total_mallocs, size_t total_frees, size_t overall_peak) {
100                        std::cerr << std::setw(nc) << stat.name;
101                        std::cerr << " | ";
102
103                        print(stat.mallocs,     total_mallocs);
104                        print(stat.frees,       total_frees  );
105                        print(stat.peak_allocs, overall_peak );
106                        std::cerr << "\n";
107                }
108
109                void print(char c, size_t nc) {
110                        for(size_t i = 0; i < nc; i++) {
111                                std::cerr << c;
112                        }
113                        std::cerr << '\n';
114                }
115
116                void print() {
117                        if(!enabled) return;
118
119                        size_t nc = 0;
120                        size_t total_mallocs = 0;
121                        size_t total_frees   = 0;
122                        size_t overall_peak  = 0;
123                        for(size_t i = 0; i < passes_cnt; i++) {
124                                nc = std::max(nc, std::strlen(passes[i].name));
125                                total_mallocs += passes[i].mallocs;
126                                total_frees   += passes[i].frees;
127                                overall_peak = std::max(overall_peak, passes[i].peak_allocs);
128                        }
129                        size_t nct = nc + 65;
130
131                        const char * const title = "Heap Usage Statistic";
132                        print('=', nct);
133                        for(size_t i = 0; i < (nct - std::strlen(title)) / 2; i++) std::cerr << ' ';
134                        std::cerr << title << std::endl;
135                        print('-', nct);
136                        std::cerr << std::setw(nc) << "Pass";
137                        std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
138
139                        print('-', nct);
140                        for(size_t i = 0; i < passes_cnt; i++) {
141                                print(passes[i], nc, total_mallocs, total_frees, overall_peak);
142                        }
143
144                        print('-', nct);
145                        std::cerr << std::setw(nc) << "Trace";
146                        std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
147
148                        print('-', nct);
149                        for (size_t i = 0; i < stacktrace_stats_count; i++) {
150                                print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak);
151                        }
152                        print('-', nct);
153                        print({"Sum", total_mallocs, total_frees, 0, overall_peak},
154                                nc, total_mallocs, total_frees, overall_peak);
155
156                }
157
158#include <stdarg.h>
159#include <stddef.h>
160#include <stdio.h>
161#include <string.h>
162#include <unistd.h>
163#include <signal.h>
164                extern "C" {
165#include <dlfcn.h>
166#include <execinfo.h>
167                }
168
169        //=============================================================================================
170        // Interposing helpers
171        //=============================================================================================
172
173                typedef void (* generic_fptr_t)(void);
174                generic_fptr_t interpose_symbol( const char * symbol, const char * version ) {
175                        const char * error;
176
177                        static void * library;
178                        if ( ! library ) {
179#                               if defined( RTLD_NEXT )
180                                        library = RTLD_NEXT;
181#                               else
182                                        // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
183                                        library = dlopen( "libc.so.6", RTLD_LAZY );
184                                        error = dlerror();
185                                        if ( error ) {
186                                                std::cerr << "interpose_symbol : failed to open libc, " << error << std::endl;
187                                                abort();
188                                        }
189#                               endif // RTLD_NEXT
190                        } // if
191
192                        generic_fptr_t fptr;
193
194#                       if defined( _GNU_SOURCE )
195                                if ( version ) {
196                                        fptr = (generic_fptr_t)dlvsym( library, symbol, version );
197                                } else {
198                                        fptr = (generic_fptr_t)dlsym( library, symbol );
199                                }
200#                       else
201                                fptr = (generic_fptr_t)dlsym( library, symbol );
202#                       endif // _GNU_SOURCE
203
204                        error = dlerror();
205                        if ( error ) {
206                                std::cerr << "interpose_symbol : internal error, " << error << std::endl;
207                                abort();
208                        }
209
210                        return fptr;
211                }
212
213                extern "C" {
214                        void * malloc( size_t size ) __attribute__((malloc));
215                        void * malloc( size_t size ) {
216                                static auto __malloc = reinterpret_cast<void * (*)(size_t)>(interpose_symbol( "malloc", nullptr ));
217                                if( enabled && passes_cnt > 0 ) {
218                                        passes[passes_cnt - 1].mallocs++;
219                                        passes[passes_cnt - 1].n_allocs++;
220                                        passes[passes_cnt - 1].peak_allocs
221                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
222                                }
223
224                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
225                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
226                                }
227                                return __malloc( size );
228                        }
229
230                        void free( void * ptr ) {
231                                static auto __free = reinterpret_cast<void   (*)(void *)>(interpose_symbol( "free", nullptr ));
232                                if( enabled && passes_cnt > 0 ) {
233                                        passes[passes_cnt - 1].frees++;
234                                        passes[passes_cnt - 1].n_allocs--;
235                                }
236                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
237                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
238                                }
239                                return __free( ptr );
240                        }
241
242                        void * calloc( size_t nelem, size_t size ) {
243                                static auto __calloc = reinterpret_cast<void * (*)(size_t, size_t)>(interpose_symbol( "calloc", nullptr ));
244                                if( enabled && passes_cnt > 0 ) {
245                                        passes[passes_cnt - 1].mallocs++;
246                                        passes[passes_cnt - 1].n_allocs++;
247                                        passes[passes_cnt - 1].peak_allocs
248                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
249                                }
250                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
251                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
252                                }
253                                return __calloc( nelem, size );
254                        }
255
256                        void * realloc( void * ptr, size_t size ) {
257                                static auto __realloc = reinterpret_cast<void * (*)(void *, size_t)>(interpose_symbol( "realloc", nullptr ));
258                                void * s = __realloc( ptr, size );
259                                if ( enabled && s != ptr && passes_cnt > 0 ) {                  // did realloc get new storage ?
260                                        passes[passes_cnt - 1].mallocs++;
261                                        passes[passes_cnt - 1].frees++;
262                                } // if
263                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
264                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
265                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
266                                }
267                                return s;
268                        }
269                }
270#endif
271        }
272}
Note: See TracBrowser for help on using the repository browser.