aGrUM  0.13.2
debug.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005 by Pierre-Henri WUILLEMIN and Christophe GONZALES *
3  * {prenom.nom}_at_lip6.fr *
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 2 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 *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
27 #include <agrum/agrum.h>
28 
29 #include <algorithm>
30 #include <iomanip>
31 #include <iostream>
32 #include <sstream>
33 #include <string>
34 #include <vector>
35 #include <mutex>
36 
37 #ifndef DOXYGEN_SHOULD_SKIP_THIS
38 
39 # include <map>
40 
41 namespace gum {
42 
43 # ifndef NDEBUG
44 
45  namespace __debug__ {
46  typedef std::map< std::string, int > DEBUG_MAP;
47 
48  static std::mutex debug_mutex;
49 
50  // this static hashtable only on debug mode.
51  static DEBUG_MAP& __sizeof() {
52  // This function is not thread-safe ! (but only in debug mode)
53  static DEBUG_MAP* sizeOf = new DEBUG_MAP();
54  return *sizeOf;
55  }
56 
57  // this static hashtable only on debug mode.
58  static DEBUG_MAP& __creation() {
59  // @todo This function is not thread-safe ! (but only in debug mode)
60  static DEBUG_MAP* creation = new DEBUG_MAP();
61  return *creation;
62  }
63 
64  static DEBUG_MAP& __deletion() {
65  // @todo This function is not thread-safe ! (but only in debug mode)
66  static DEBUG_MAP* deletion = new DEBUG_MAP();
67  return *deletion;
68  }
69 
70  std::string __getFile(const char* f) {
71  std::string s(f);
72  return s.erase(0, s.rfind("/") + 1);
73  }
74 
75  void __show_trace(const char* zeKey,
76  const char* zeFile,
77  long zeLine,
78  const char* zeMsg,
79  const void* zePtr) {
80 # ifdef GUM_DEEP_TRACE_ON
81  std::cerr << std::setw(40) << std::setfill(' ') << __getFile(zeFile) << "#"
82  << std::setfill('0') << std::setw(5) << std::dec << zeLine << " : "
83  << zeMsg << " <" << zeKey << "> [" << std::hex << zePtr << "]"
84  << std::dec << std::endl;
85 # endif // TRACE_CONSTRUCTION_ON
86  }
87 
88  void __inc_creation(const char* zeKey,
89  const char* zeFile,
90  long zeLine,
91  const char* zeMsg,
92  const void* zePtr,
93  int zeSize) {
94  debug_mutex.lock();
95  __show_trace(zeKey, zeFile, zeLine, zeMsg, zePtr);
96  __creation()[zeKey]++;
97  __sizeof()[zeKey] = zeSize;
98  debug_mutex.unlock();
99  }
100 
101  // to handle static element of agrum library
102  void __dec_creation(const char* zeKey,
103  const char* zeFile,
104  long zeLine,
105  const char* zeMsg,
106  const void* zePtr) {
107  debug_mutex.lock();
108  __show_trace(zeKey, zeFile, zeLine, zeMsg, zePtr);
109  __creation()[zeKey]--;
110  debug_mutex.unlock();
111  }
112 
113  void __inc_deletion(const char* zeKey,
114  const char* zeFile,
115  long zeLine,
116  const char* zeMsg,
117  const void* zePtr) {
118  debug_mutex.lock();
119  __show_trace(zeKey, zeFile, zeLine, zeMsg, zePtr);
120  __deletion()[zeKey]++;
121  debug_mutex.unlock();
122  }
123 
124  void __dumpObjects() {
125  Size nb_err = 0;
126  double total_size = 0.0;
127 
128  char fillChar = '_';
129  int widthColLibelle = 50;
130  int widthColSizeOf = 5;
131  int widthColItemsNumber = 8;
132 
133  std::cout << std::setfill('=') << "|" << std::setw(widthColLibelle + 2) << ""
134  << "|" << std::setw(widthColSizeOf + 4) << ""
135  << "|" << std::setw(widthColItemsNumber + 2) << ""
136  << "|" << std::setw(widthColItemsNumber + 2) << ""
137  << "|" << std::endl;
138  std::cout << std::setfill(' ') << "| " << std::left
139  << std::setw(widthColLibelle) << "Class Name" << std::right
140  << " | " << std::setw(widthColSizeOf) << "Size"
141  << " | " << std::setw(widthColItemsNumber) << "#Const"
142  << " | " << std::setw(widthColItemsNumber) << "#Dest"
143  << " |" << std::endl;
144  std::cout << std::setfill('-') << "|" << std::setw(widthColLibelle + 2) << ""
145  << "|" << std::setw(widthColSizeOf + 4) << ""
146  << "|" << std::setw(widthColItemsNumber + 2) << ""
147  << "|" << std::setw(widthColItemsNumber + 2) << ""
148  << "|" << std::endl;
149  // list of created objects
150  std::map< std::string, std::string > res;
151 
152  for (DEBUG_MAP::const_iterator xx = __creation().begin();
153  xx != __creation().end();
154  ++xx) {
155  std::stringstream stream;
156  int zeCreatedObjs = xx->second;
157  int zeDeletedObjts = -1;
158  int size = __sizeof()[xx->first];
159 
160  stream << std::setfill(fillChar = (fillChar == '_') ? ' ' : '_') << "| "
161  << std::setw(widthColLibelle) << std::left << xx->first << " | "
162  << std::right << std::setw(widthColSizeOf) << size << " o | "
163  << std::setw(widthColItemsNumber) << zeCreatedObjs << " | ";
164 
165  if (size > 0) total_size += zeCreatedObjs * (size / 1024.0);
166 
167  try {
168  zeDeletedObjts = __deletion()[xx->first];
169  stream << std::setfill(fillChar) << std::setw(widthColItemsNumber)
170  << zeDeletedObjts;
171  } catch (NotFound&) {
172  stream << std::setfill(fillChar) << std::setw(widthColItemsNumber)
173  << "?????";
174  }
175 
176  stream << " |";
177  ;
178 
179  if (zeCreatedObjs != zeDeletedObjts) {
180  nb_err += std::abs(zeDeletedObjts - zeCreatedObjs);
181  stream << "<--- failed";
182  }
183 
184  res.insert(make_pair(xx->first, stream.str()));
185  // res.push_back( stream.str() );
186  }
187 
188  // list of deleted objects, but not created (?)
189  for (DEBUG_MAP::const_iterator xx = __deletion().begin();
190  xx != __deletion().end();
191  ++xx) {
192  try {
193  __creation()[xx->first];
194  } catch (NotFound&) {
195  std::stringstream stream;
196  fillChar = (fillChar == '_') ? ' ' : '_';
197  stream << std::setfill(fillChar = (fillChar == '_') ? ' ' : '_') << "| "
198  << std::setw(widthColLibelle) << std::left << xx->first + " "
199  << " | " << std::right << std::setw(widthColSizeOf)
200  << __sizeof()[xx->first] << " o | "
201  << std::setw(widthColItemsNumber) << "?????"
202  << " | " << std::setw(widthColItemsNumber) << xx->second
203  << " |<--- failed";
204  res.insert(make_pair(xx->first, stream.str()));
205  // res.push_back( stream.str() );
206  nb_err += xx->second;
207  }
208  }
209 
210  for (const auto iter : res) {
211  std::cout << iter.second << std::endl;
212  }
213 
214  std::cout << std::setfill('-');
215 
216  std::cout << "|-" << std::setw(widthColLibelle) << ""
217  << "-|-" << std::setw(widthColSizeOf + 2) << ""
218  << "-|-" << std::setw(widthColItemsNumber) << ""
219  << "-|-" << std::setw(widthColItemsNumber) << ""
220  << "-|" << std::endl;
221 
222  std::cout << std::setfill(' ');
223 
224  if (nb_err == 0) {
225  std::cout << "| " << std::setw(widthColLibelle) << "NO MEMORY LEAK !"
226  << " | "
227  << std::setw(widthColSizeOf + widthColItemsNumber * 2 + 9) << ""
228  << "|" << std::endl;
229  } else {
230  std::cout << "| " << std::setw(widthColLibelle) << "Memory leaks found "
231  << ""
232  << " | "
233  << std::setw(widthColSizeOf + widthColItemsNumber * 2 - 6)
234  << nb_err << " object(s) "
235  << "|" << std::endl;
236  }
237 
238  std::cout << "| " << std::setw(widthColLibelle) << "total "
239  << " | " << std::fixed
240  << std::setw(widthColSizeOf + widthColItemsNumber * 2 - 4)
241  << std::setprecision(2) << total_size << " Ko "
242  << "|" << std::endl;
243 
244  std::cout << std::setfill('=') << "|" << std::setw(widthColLibelle + 2) << ""
245  << "|" << std::setw(widthColSizeOf + widthColItemsNumber * 2 + 10)
246  << ""
247  << "|" << std::endl;
248  }
249 
250  // take into account static objects in agrum (no called destructor before
251  // exit())
252  void __staticCorrections() {}
253 
254  void __atexit() {
255  __staticCorrections();
256  __dumpObjects();
257  __creation().clear();
258  __deletion().clear();
259  }
260 
261  } // namespace __debug__
262 
263 # endif // NDEBUG
264 
265 } /* namespace gum */
266 
267 #endif // DOXYGEN_SHOULD_SKIP_THIS
unsigned long Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:50
void __atexit()
Used for debug purpose.
Definition: utils_misc.cpp:41
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25