2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 // This class is a memory allocation tracker used to optimize
21 // the memory usage and find memory leaks.
24 #include "gnashconfig.h"
27 // If we don't have support for mallinfo(), this code is useless
34 #include "getclocktime.hpp"
40 RcInitFile
& rcfile
= gnash::RcInitFile::getDefaultInstance();
43 const int DATALOG_SIZE
= 1024;
51 // GNASH_REPORT_FUNCTION;
55 Memory::Memory(size_t size
)
58 // GNASH_REPORT_FUNCTION;
60 _info
= new struct small_mallinfo
[_size
];
66 // GNASH_REPORT_FUNCTION;
74 // Erase all collected data and reset collections.
78 // GNASH_REPORT_FUNCTION;
80 memset(_info
, 0, _size
);
89 // GNASH_REPORT_FUNCTION;
92 log_debug("Allocating buffer for %d data samples", _size
);
93 _info
= new struct small_mallinfo
[_size
];
100 Memory::addStats(int line
)
102 // GNASH_REPORT_FUNCTION;
104 struct small_mallinfo
*ptr
= _info
+ _index
;
114 // GNASH_REPORT_FUNCTION;
116 struct small_mallinfo
*ptr
= _info
+ _index
;
125 Memory::addStats(struct small_mallinfo
*ptr
)
127 // GNASH_REPORT_FUNCTION;
128 return addStats(ptr
, 0);
132 Memory::addStats(struct small_mallinfo
*ptr
, int line
)
134 // GNASH_REPORT_FUNCTION;
135 struct mallinfo mal
= mallinfo();
136 int yy
= static_cast<int>(_size
);
139 if ((ptr
) && (_index
< yy
)) {
141 clock_gettime (CLOCK_REALTIME
, &ptr
->stamp
);
142 ptr
->arena
= mal
.arena
;
143 ptr
->uordblks
= mal
.uordblks
;
144 ptr
->fordblks
= mal
.fordblks
;
151 // return true if we haven't leaked any memory
153 Memory::endCheckpoint()
155 // GNASH_REPORT_FUNCTION;
156 _checkpoint
[1] = mallinfo();
157 if (_checkpoint
[1].uordblks
== _checkpoint
[0].uordblks
) {
164 // Dump the differences of bytes allocated between two samples
168 // GNASH_REPORT_FUNCTION;
169 return diffStats(_index
- 1, _index
- 2);
173 Memory::diffStats(int x
, int y
)
175 // GNASH_REPORT_FUNCTION;
176 int yy
= static_cast<int>(_size
);
177 if ((_info
) && (x
< DATALOG_SIZE
) && (y
< yy
)) {
178 return (_info
[x
].uordblks
- _info
[y
].uordblks
);
183 // Dump the differences between two samples's timestamp
187 // GNASH_REPORT_FUNCTION;
188 return diffStamp(_index
- 1, _index
- 2);
192 Memory::diffStamp(int x
, int y
)
194 // GNASH_REPORT_FUNCTION;
195 int yy
= static_cast<int>(_size
);
196 if ((_info
) && (x
< DATALOG_SIZE
) && (y
< yy
)) {
197 return (_info
[x
].stamp
.tv_nsec
- _info
[y
].stamp
.tv_nsec
);
202 // Analyze memory usage
206 // GNASH_REPORT_FUNCTION;
208 int accumulate_allocated
= 0;
209 int accumulate_freed
= 0;
211 // System memory is what we get from brk(), the lowest level
212 // system call used by both malloc() or new().
213 cerr
<< endl
<< "System memory allocated in bytes: "
214 << _info
->arena
<< endl
;
215 int diff_arena
= (_info
+ _index
- 1)->arena
- _info
->arena
;
217 cerr
<< "System memory change in bytes: " << diff_arena
<< endl
;
220 int total_allocated
= (_info
+ _index
- 1)->uordblks
- _info
->uordblks
;
221 cerr
<< "Total bytes allocated: " << total_allocated
<< endl
;
224 for (int i
=1; i
<_index
; i
++) {
225 struct small_mallinfo
*ptr
= _info
+ i
;
227 // // Get the time stamp
228 // int diff_stamp_sec = (ptr->stamp.tv_sec) - (ptr - 1)->stamp.tv_sec;
229 int diff_stamp_nsec
= (ptr
->stamp
.tv_nsec
) - (ptr
- 1)->stamp
.tv_nsec
;
230 // if ((diff_stamp_sec > 0) || (diff_stamp_nsec > 0)) {
231 // if (ptr->line && (ptr - 1)->line) {
232 // if (diff_stamp_sec > 0) {
233 // cerr << "Difference in seconds is: " << diff_stamp_sec;
234 // cerr << ", nanoseconds is: "<< diff_stamp_nsec;
237 // cerr << "Difference in nanoseconds is: "<< diff_stamp_nsec;
239 // cerr << "\tbetween lines: " << (ptr - 1)->line
240 // << " and " << ptr->line << endl;
242 // cerr << "Difference in seconds is: " << diff_stamp_sec
243 // << ", nanoseconds is: "<< diff_stamp_nsec << endl;
246 // See what was allocated between samples
247 int diff_allocated
= (ptr
->uordblks
) - (ptr
- 1)->uordblks
;
248 if (diff_allocated
> 0) {
249 accumulate_allocated
+= diff_allocated
;
250 if (ptr
->line
&& (ptr
- 1)->line
) {
251 cerr
<< "Allocated " << diff_allocated
252 << " bytes\tbetween lines: " << (ptr
- 1)->line
253 << " and " << ptr
->line
;
255 cerr
<< "Allocated bytes: " << diff_allocated
;
257 // same as diff_freed
259 // if (diff_allocated != 0) {
260 // cerr << "\tnew heap bytes: " << diff_allocated << endl;
264 // See what was freed between samples
265 int diff_freed
= ptr
->fordblks
- (ptr
- 1)->fordblks
;
266 if (diff_freed
> 0) {
267 accumulate_freed
+= diff_freed
;
268 if (ptr
->line
&& (ptr
- 1)->line
) {
269 cerr
<< "Freed " << diff_freed
270 << " bytes between lines: " << (ptr
- 1)->line
271 << " and " << ptr
->line
;
273 cerr
<< "Freed bytes: " << diff_freed
;
275 // Same as diif_allocated
277 // if (diff_freed != 0) {
278 // cerr << "\tnuked heap bytes: " << diff_freed << endl;
281 if (diff_freed
|| diff_allocated
) {
282 cerr
<< ", and took " << diff_stamp_nsec
<< " nanoseconds";
284 cerr
<< "no allocations, time difference is " << diff_stamp_nsec
<< " nanoseconds";
285 if (ptr
->line
&& (ptr
- 1)->line
) {
286 cerr
<< " between lines: " << (ptr
- 1)->line
287 << " and " << ptr
->line
;
293 cerr
<< "Only have one sample" << endl
;
297 // Sanity check on our calculations
298 if (total_allocated
!= (accumulate_allocated
- accumulate_freed
)) {
299 log_error("Calculations don't equal");
301 log_debug("Zero memory leaks for this program");
303 if ((_checkpoint
[0].uordblks
!= 0) && (_checkpoint
[1].uordblks
!= 0)) {
304 if (_checkpoint
[1].uordblks
== _checkpoint
[0].uordblks
) {
305 cerr
<< "The last checkpoint status was: "
306 << ((_checkpoint
[1].uordblks
== _checkpoint
[0].uordblks
)
307 ? "passed" : "failed") << endl
;
314 // Dump the vector of stored classes
316 Memory::dump(struct mallinfo
*ptr
)
318 // GNASH_REPORT_FUNCTION;
319 cerr
<< "\tstruct mallinfo: Non-mmapped space allocated from system is: \""
320 << ptr
->arena
<< "\"" << endl
;
321 cerr
<< "\tstruct mallinfo: Total allocated space is: \""
322 << ptr
->uordblks
<< "\"" << endl
;
323 cerr
<< "\tstruct mallinfo: Total free space is: \""
324 << ptr
->fordblks
<< "\"" << endl
;
327 // Dump the vector of stored classes
329 Memory::dump(struct small_mallinfo
*ptr
)
331 // GNASH_REPORT_FUNCTION;
332 cerr
<< "\tLine number of sample: " << ptr
->line
<< endl
;
335 cerr
<< "\tTimestamp number of sample: " << ptr
->stamp
.tv_sec
336 << ":" << ptr
->stamp
.tv_nsec
<< endl
;
339 cerr
<< "\tNon-mmapped space allocated from system is: \""
340 << ptr
->arena
<< "\"" << endl
;
341 cerr
<< "\tTotal allocated space is: \""
342 << ptr
->uordblks
<< "\"" << endl
;
343 cerr
<< "\tTotal free space is: \""
344 << ptr
->fordblks
<< "\"" << endl
;
350 // GNASH_REPORT_FUNCTION;
352 for (int i
=0; i
<_index
; i
++) {
353 cerr
<< "Mallinfo index: " << i
<< endl
;
361 // GNASH_REPORT_FUNCTION;
363 struct small_mallinfo
*ptr
;
364 cerr
<< "linenum,seconds,nanoseconds,arena,allocated,freed" << endl
;
365 for (int i
=0; i
<_index
; i
++) {
367 cerr
<< ptr
->line
<< ","
368 << ptr
->stamp
.tv_sec
<< ","
369 << ptr
->stamp
.tv_nsec
<< ","
371 << ptr
->uordblks
<< ","
372 << ptr
->fordblks
<< endl
;
376 } // end of gnash namespace
378 #endif // end of HAVE_MALLINFO
382 // indent-tabs-mode: t