source: src/Common/Stats/Heap.cc@ 37b7d95

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 37b7d95 was c15085d, checked in by Fangren Yu <f37yu@…>, 5 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.