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
36 #include "getclocktime.hpp"
42 RcInitFile
& rcfile
= gnash::RcInitFile::getDefaultInstance();
45 const int DATALOG_SIZE
= 1024;
53 // GNASH_REPORT_FUNCTION;
57 Memory::Memory(size_t size
)
60 // GNASH_REPORT_FUNCTION;
62 _info
= new struct small_mallinfo
[_size
];
68 // GNASH_REPORT_FUNCTION;
76 // Erase all collected data and reset collections.
80 // GNASH_REPORT_FUNCTION;
82 memset(_info
, 0, _size
);
91 // GNASH_REPORT_FUNCTION;
94 log_debug("Allocating buffer for %d data samples", _size
);
95 _info
= new struct small_mallinfo
[_size
];
102 Memory::addStats(int line
)
104 // GNASH_REPORT_FUNCTION;
106 struct small_mallinfo
*ptr
= _info
+ _index
;
116 // GNASH_REPORT_FUNCTION;
118 struct small_mallinfo
*ptr
= _info
+ _index
;
127 Memory::addStats(struct small_mallinfo
*ptr
)
129 // GNASH_REPORT_FUNCTION;
130 return addStats(ptr
, 0);
134 Memory::addStats(struct small_mallinfo
*ptr
, int line
)
136 // GNASH_REPORT_FUNCTION;
137 struct mallinfo mal
= mallinfo();
138 int yy
= static_cast<int>(_size
);
141 if ((ptr
) && (_index
< yy
)) {
143 clock_gettime (CLOCK_REALTIME
, &ptr
->stamp
);
144 ptr
->arena
= mal
.arena
;
145 ptr
->uordblks
= mal
.uordblks
;
146 ptr
->fordblks
= mal
.fordblks
;
153 // return true if we haven't leaked any memory
155 Memory::endCheckpoint()
157 // GNASH_REPORT_FUNCTION;
158 _checkpoint
[1] = mallinfo();
159 if (_checkpoint
[1].uordblks
== _checkpoint
[0].uordblks
) {
166 // Dump the differences of bytes allocated between two samples
170 // GNASH_REPORT_FUNCTION;
171 return diffStats(_index
- 1, _index
- 2);
175 Memory::diffStats(int x
, int y
)
177 // GNASH_REPORT_FUNCTION;
178 int yy
= static_cast<int>(_size
);
179 if ((_info
) && (x
< DATALOG_SIZE
) && (y
< yy
)) {
180 return (_info
[x
].uordblks
- _info
[y
].uordblks
);
185 // Dump the differences between two samples's timestamp
189 // GNASH_REPORT_FUNCTION;
190 return diffStamp(_index
- 1, _index
- 2);
194 Memory::diffStamp(int x
, int y
)
196 // GNASH_REPORT_FUNCTION;
197 int yy
= static_cast<int>(_size
);
198 if ((_info
) && (x
< DATALOG_SIZE
) && (y
< yy
)) {
199 return (_info
[x
].stamp
.tv_nsec
- _info
[y
].stamp
.tv_nsec
);
204 // Analyze memory usage
208 // GNASH_REPORT_FUNCTION;
210 int accumulate_allocated
= 0;
211 int accumulate_freed
= 0;
213 // System memory is what we get from brk(), the lowest level
214 // system call used by both malloc() or new().
215 cerr
<< endl
<< "System memory allocated in bytes: "
216 << _info
->arena
<< endl
;
217 int diff_arena
= (_info
+ _index
- 1)->arena
- _info
->arena
;
219 cerr
<< "System memory change in bytes: " << diff_arena
<< endl
;
222 int total_allocated
= (_info
+ _index
- 1)->uordblks
- _info
->uordblks
;
223 cerr
<< "Total bytes allocated: " << total_allocated
<< endl
;
226 for (int i
=1; i
<_index
; i
++) {
227 struct small_mallinfo
*ptr
= _info
+ i
;
229 // // Get the time stamp
230 // int diff_stamp_sec = (ptr->stamp.tv_sec) - (ptr - 1)->stamp.tv_sec;
231 int diff_stamp_nsec
= (ptr
->stamp
.tv_nsec
) - (ptr
- 1)->stamp
.tv_nsec
;
232 // if ((diff_stamp_sec > 0) || (diff_stamp_nsec > 0)) {
233 // if (ptr->line && (ptr - 1)->line) {
234 // if (diff_stamp_sec > 0) {
235 // cerr << "Difference in seconds is: " << diff_stamp_sec;
236 // cerr << ", nanoseconds is: "<< diff_stamp_nsec;
239 // cerr << "Difference in nanoseconds is: "<< diff_stamp_nsec;
241 // cerr << "\tbetween lines: " << (ptr - 1)->line
242 // << " and " << ptr->line << endl;
244 // cerr << "Difference in seconds is: " << diff_stamp_sec
245 // << ", nanoseconds is: "<< diff_stamp_nsec << endl;
248 // See what was allocated between samples
249 int diff_allocated
= (ptr
->uordblks
) - (ptr
- 1)->uordblks
;
250 if (diff_allocated
> 0) {
251 accumulate_allocated
+= diff_allocated
;
252 if (ptr
->line
&& (ptr
- 1)->line
) {
253 cerr
<< "Allocated " << diff_allocated
254 << " bytes\tbetween lines: " << (ptr
- 1)->line
255 << " and " << ptr
->line
;
257 cerr
<< "Allocated bytes: " << diff_allocated
;
259 // same as diff_freed
261 // if (diff_allocated != 0) {
262 // cerr << "\tnew heap bytes: " << diff_allocated << endl;
266 // See what was freed between samples
267 int diff_freed
= ptr
->fordblks
- (ptr
- 1)->fordblks
;
268 if (diff_freed
> 0) {
269 accumulate_freed
+= diff_freed
;
270 if (ptr
->line
&& (ptr
- 1)->line
) {
271 cerr
<< "Freed " << diff_freed
272 << " bytes between lines: " << (ptr
- 1)->line
273 << " and " << ptr
->line
;
275 cerr
<< "Freed bytes: " << diff_freed
;
277 // Same as diif_allocated
279 // if (diff_freed != 0) {
280 // cerr << "\tnuked heap bytes: " << diff_freed << endl;
283 if (diff_freed
|| diff_allocated
) {
284 cerr
<< ", and took " << diff_stamp_nsec
<< " nanoseconds";
286 cerr
<< "no allocations, time difference is " << diff_stamp_nsec
<< " nanoseconds";
287 if (ptr
->line
&& (ptr
- 1)->line
) {
288 cerr
<< " between lines: " << (ptr
- 1)->line
289 << " and " << ptr
->line
;
295 cerr
<< "Only have one sample" << endl
;
299 // Sanity check on our calculations
300 if (total_allocated
!= (accumulate_allocated
- accumulate_freed
)) {
301 log_error("Calculations don't equal");
303 log_debug("Zero memory leaks for this program");
305 if ((_checkpoint
[0].uordblks
!= 0) && (_checkpoint
[1].uordblks
!= 0)) {
306 if (_checkpoint
[1].uordblks
== _checkpoint
[0].uordblks
) {
307 cerr
<< "The last checkpoint status was: "
308 << ((_checkpoint
[1].uordblks
== _checkpoint
[0].uordblks
)
309 ? "passed" : "failed") << endl
;
316 // Dump the vector of stored classes
318 Memory::dump(struct mallinfo
*ptr
)
320 // GNASH_REPORT_FUNCTION;
321 cerr
<< "\tstruct mallinfo: Non-mmapped space allocated from system is: \""
322 << ptr
->arena
<< "\"" << endl
;
323 cerr
<< "\tstruct mallinfo: Total allocated space is: \""
324 << ptr
->uordblks
<< "\"" << endl
;
325 cerr
<< "\tstruct mallinfo: Total free space is: \""
326 << ptr
->fordblks
<< "\"" << endl
;
329 // Dump the vector of stored classes
331 Memory::dump(struct small_mallinfo
*ptr
)
333 // GNASH_REPORT_FUNCTION;
334 cerr
<< "\tLine number of sample: " << ptr
->line
<< endl
;
337 cerr
<< "\tTimestamp number of sample: " << ptr
->stamp
.tv_sec
338 << ":" << ptr
->stamp
.tv_nsec
<< endl
;
341 cerr
<< "\tNon-mmapped space allocated from system is: \""
342 << ptr
->arena
<< "\"" << endl
;
343 cerr
<< "\tTotal allocated space is: \""
344 << ptr
->uordblks
<< "\"" << endl
;
345 cerr
<< "\tTotal free space is: \""
346 << ptr
->fordblks
<< "\"" << endl
;
352 // GNASH_REPORT_FUNCTION;
354 for (int i
=0; i
<_index
; i
++) {
355 cerr
<< "Mallinfo index: " << i
<< endl
;
363 // GNASH_REPORT_FUNCTION;
365 struct small_mallinfo
*ptr
;
366 cerr
<< "linenum,seconds,nanoseconds,arena,allocated,freed" << endl
;
367 for (int i
=0; i
<_index
; i
++) {
369 cerr
<< ptr
->line
<< ","
370 << ptr
->stamp
.tv_sec
<< ","
371 << ptr
->stamp
.tv_nsec
<< ","
373 << ptr
->uordblks
<< ","
374 << ptr
->fordblks
<< endl
;
378 } // end of gnash namespace
380 #endif // end of HAVE_MALLINFO
384 // indent-tabs-mode: t