drop Build-Depends from mysql extension package
[gnash.git] / libbase / memory.cpp
bloba2f80b80cbf2e97133d079fddc60877391f727be
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 <vector>
32 #include "log.h"
33 #include "gmemory.h"
34 #include "getclocktime.hpp"
36 using namespace std;
38 namespace gnash {
40 RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
43 const int DATALOG_SIZE = 1024;
45 Memory::Memory()
46 : _collecting(false),
47 _info(0),
48 _size(DATALOG_SIZE),
49 _index(0)
51 // GNASH_REPORT_FUNCTION;
55 Memory::Memory(size_t size)
56 : _collecting(false)
58 // GNASH_REPORT_FUNCTION;
59 _size = size;
60 _info = new struct small_mallinfo[_size];
61 reset();
64 Memory::~Memory()
66 // GNASH_REPORT_FUNCTION;
67 if (_info) {
68 delete[] _info;
70 _index = 0;
71 _size = 0;
74 // Erase all collected data and reset collections.
75 void
76 Memory::reset()
78 // GNASH_REPORT_FUNCTION;
79 if (_info) {
80 memset(_info, 0, _size);
82 _index = 0;
86 void
87 Memory::startStats()
89 // GNASH_REPORT_FUNCTION;
90 _collecting = true;
91 if (_info == 0) {
92 log_debug("Allocating buffer for %d data samples", _size);
93 _info = new struct small_mallinfo[_size];
94 reset();
95 addStats();
99 int
100 Memory::addStats(int line)
102 // GNASH_REPORT_FUNCTION;
103 if (_info) {
104 struct small_mallinfo *ptr = _info + _index;
105 addStats(ptr, line);
108 return _index;
112 Memory::addStats()
114 // GNASH_REPORT_FUNCTION;
115 if (_info) {
116 struct small_mallinfo *ptr = _info + _index;
117 addStats(ptr, 0);
120 return _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);
138 // dump(&mal);
139 if ((ptr) && (_index < yy)) {
140 ptr->line = line;
141 clock_gettime (CLOCK_REALTIME, &ptr->stamp);
142 ptr->arena = mal.arena;
143 ptr->uordblks = mal.uordblks;
144 ptr->fordblks = mal.fordblks;
145 _index++;
148 return _index;
151 // return true if we haven't leaked any memory
152 bool
153 Memory::endCheckpoint()
155 // GNASH_REPORT_FUNCTION;
156 _checkpoint[1] = mallinfo();
157 if (_checkpoint[1].uordblks == _checkpoint[0].uordblks) {
158 return true;
161 return false;
164 // Dump the differences of bytes allocated between two samples
166 Memory::diffStats()
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);
180 return -1;
183 // Dump the differences between two samples's timestamp
185 Memory::diffStamp()
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);
199 return -1;
202 // Analyze memory usage
203 bool
204 Memory::analyze()
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;
216 if (diff_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;
223 if (_index > 1) {
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;
235 // }
236 // else {
237 // cerr << "Difference in nanoseconds is: "<< diff_stamp_nsec;
238 // }
239 // cerr << "\tbetween lines: " << (ptr - 1)->line
240 // << " and " << ptr->line << endl;
241 // } else {
242 // cerr << "Difference in seconds is: " << diff_stamp_sec
243 // << ", nanoseconds is: "<< diff_stamp_nsec << endl;
244 // }
245 // }
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;
254 } else {
255 cerr << "Allocated bytes: " << diff_allocated;
257 // same as diff_freed
258 // } else {
259 // if (diff_allocated != 0) {
260 // cerr << "\tnew heap bytes: " << diff_allocated << endl;
261 // }
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;
272 } else {
273 cerr << "Freed bytes: " << diff_freed;
275 // Same as diif_allocated
276 // } else {
277 // if (diff_freed != 0) {
278 // cerr << "\tnuked heap bytes: " << diff_freed << endl;
279 // }
281 if (diff_freed || diff_allocated) {
282 cerr << ", and took " << diff_stamp_nsec << " nanoseconds";
283 } else {
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;
290 cerr << endl;
292 } else {
293 cerr << "Only have one sample" << endl;
294 dump();
297 // Sanity check on our calculations
298 if (total_allocated != (accumulate_allocated - accumulate_freed)) {
299 log_error("Calculations don't equal");
300 } else {
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;
310 return true;
314 // Dump the vector of stored classes
315 void
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
328 void
329 Memory::dump(struct small_mallinfo *ptr)
331 // GNASH_REPORT_FUNCTION;
332 cerr << "\tLine number of sample: " << ptr->line << endl;
333 cout.fill('0');
334 cout.width(9);
335 cerr << "\tTimestamp number of sample: " << ptr->stamp.tv_sec
336 << ":" << ptr->stamp.tv_nsec << endl;
337 cout.fill(' ');
338 cout.width(1);
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;
347 void
348 Memory::dump()
350 // GNASH_REPORT_FUNCTION;
352 for (int i=0; i<_index; i++) {
353 cerr << "Mallinfo index: " << i << endl;
354 dump(_info + i);
358 void
359 Memory::dumpCSV()
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++) {
366 ptr = _info + i;
367 cerr << ptr->line << ","
368 << ptr->stamp.tv_sec << ","
369 << ptr->stamp.tv_nsec << ","
370 << ptr->arena << ","
371 << ptr->uordblks << ","
372 << ptr->fordblks << endl;
376 } // end of gnash namespace
378 #endif // end of HAVE_MALLINFO
380 // Local Variables:
381 // mode: C++
382 // indent-tabs-mode: t
383 // End: