reduce verbosity
[gnash.git] / libbase / memory.cpp
blob921c9ddf9bbf923300b9b93dfca50dc2e915a0bb
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
3 // Foundation, Inc
4 //
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.
9 //
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.
14 //
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.
23 #ifdef HAVE_CONFIG_H
24 #include "gnashconfig.h"
25 #endif
27 // If we don't have support for mallinfo(), this code is useless
28 #if HAVE_MALLINFO
30 #include "gmemory.h"
32 #include <vector>
33 #include <iostream>
35 #include "log.h"
36 #include "getclocktime.hpp"
38 using namespace std;
40 namespace gnash {
42 RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
45 const int DATALOG_SIZE = 1024;
47 Memory::Memory()
48 : _collecting(false),
49 _info(0),
50 _size(DATALOG_SIZE),
51 _index(0)
53 // GNASH_REPORT_FUNCTION;
57 Memory::Memory(size_t size)
58 : _collecting(false)
60 // GNASH_REPORT_FUNCTION;
61 _size = size;
62 _info = new struct small_mallinfo[_size];
63 reset();
66 Memory::~Memory()
68 // GNASH_REPORT_FUNCTION;
69 if (_info) {
70 delete[] _info;
72 _index = 0;
73 _size = 0;
76 // Erase all collected data and reset collections.
77 void
78 Memory::reset()
80 // GNASH_REPORT_FUNCTION;
81 if (_info) {
82 memset(_info, 0, _size);
84 _index = 0;
88 void
89 Memory::startStats()
91 // GNASH_REPORT_FUNCTION;
92 _collecting = true;
93 if (_info == 0) {
94 log_debug("Allocating buffer for %d data samples", _size);
95 _info = new struct small_mallinfo[_size];
96 reset();
97 addStats();
102 Memory::addStats(int line)
104 // GNASH_REPORT_FUNCTION;
105 if (_info) {
106 struct small_mallinfo *ptr = _info + _index;
107 addStats(ptr, line);
110 return _index;
114 Memory::addStats()
116 // GNASH_REPORT_FUNCTION;
117 if (_info) {
118 struct small_mallinfo *ptr = _info + _index;
119 addStats(ptr, 0);
122 return _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);
140 // dump(&mal);
141 if ((ptr) && (_index < yy)) {
142 ptr->line = line;
143 clock_gettime (CLOCK_REALTIME, &ptr->stamp);
144 ptr->arena = mal.arena;
145 ptr->uordblks = mal.uordblks;
146 ptr->fordblks = mal.fordblks;
147 _index++;
150 return _index;
153 // return true if we haven't leaked any memory
154 bool
155 Memory::endCheckpoint()
157 // GNASH_REPORT_FUNCTION;
158 _checkpoint[1] = mallinfo();
159 if (_checkpoint[1].uordblks == _checkpoint[0].uordblks) {
160 return true;
163 return false;
166 // Dump the differences of bytes allocated between two samples
168 Memory::diffStats()
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);
182 return -1;
185 // Dump the differences between two samples's timestamp
187 Memory::diffStamp()
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);
201 return -1;
204 // Analyze memory usage
205 bool
206 Memory::analyze()
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;
218 if (diff_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;
225 if (_index > 1) {
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;
237 // }
238 // else {
239 // cerr << "Difference in nanoseconds is: "<< diff_stamp_nsec;
240 // }
241 // cerr << "\tbetween lines: " << (ptr - 1)->line
242 // << " and " << ptr->line << endl;
243 // } else {
244 // cerr << "Difference in seconds is: " << diff_stamp_sec
245 // << ", nanoseconds is: "<< diff_stamp_nsec << endl;
246 // }
247 // }
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;
256 } else {
257 cerr << "Allocated bytes: " << diff_allocated;
259 // same as diff_freed
260 // } else {
261 // if (diff_allocated != 0) {
262 // cerr << "\tnew heap bytes: " << diff_allocated << endl;
263 // }
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;
274 } else {
275 cerr << "Freed bytes: " << diff_freed;
277 // Same as diif_allocated
278 // } else {
279 // if (diff_freed != 0) {
280 // cerr << "\tnuked heap bytes: " << diff_freed << endl;
281 // }
283 if (diff_freed || diff_allocated) {
284 cerr << ", and took " << diff_stamp_nsec << " nanoseconds";
285 } else {
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;
292 cerr << endl;
294 } else {
295 cerr << "Only have one sample" << endl;
296 dump();
299 // Sanity check on our calculations
300 if (total_allocated != (accumulate_allocated - accumulate_freed)) {
301 log_error("Calculations don't equal");
302 } else {
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;
312 return true;
316 // Dump the vector of stored classes
317 void
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
330 void
331 Memory::dump(struct small_mallinfo *ptr)
333 // GNASH_REPORT_FUNCTION;
334 cerr << "\tLine number of sample: " << ptr->line << endl;
335 cout.fill('0');
336 cout.width(9);
337 cerr << "\tTimestamp number of sample: " << ptr->stamp.tv_sec
338 << ":" << ptr->stamp.tv_nsec << endl;
339 cout.fill(' ');
340 cout.width(1);
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;
349 void
350 Memory::dump()
352 // GNASH_REPORT_FUNCTION;
354 for (int i=0; i<_index; i++) {
355 cerr << "Mallinfo index: " << i << endl;
356 dump(_info + i);
360 void
361 Memory::dumpCSV()
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++) {
368 ptr = _info + i;
369 cerr << ptr->line << ","
370 << ptr->stamp.tv_sec << ","
371 << ptr->stamp.tv_nsec << ","
372 << ptr->arena << ","
373 << ptr->uordblks << ","
374 << ptr->fordblks << endl;
378 } // end of gnash namespace
380 #endif // end of HAVE_MALLINFO
382 // Local Variables:
383 // mode: C++
384 // indent-tabs-mode: t
385 // End: