aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
debug.cpp
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief debugging functions
25  *
26  * @author Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
27  */
28 
29 #include <agrum/agrum.h>
30 
31 #include <algorithm>
32 #include <iomanip>
33 #include <iostream>
34 #include <sstream>
35 #include <string>
36 #include <vector>
37 #include <mutex>
38 
39 #ifndef DOXYGEN_SHOULD_SKIP_THIS
40 
41 # include <map>
42 
43 namespace gum {
44 
45 # ifdef GUM_DEBUG_MODE
46 
47  namespace __debug__ {
48  typedef std::map< std::string, int > DEBUG_MAP;
49 
50  static std::mutex debug_mutex;
51 
52  // this static hashtable only on debug mode.
53  static DEBUG_MAP& sizeof__() {
54  // This function is not thread-safe ! (but only in debug mode)
55  static DEBUG_MAP* sizeOf = new DEBUG_MAP();
56  return *sizeOf;
57  }
58 
59  // this static hashtable only on debug mode.
60  static DEBUG_MAP& creation__() {
61  // @warning This function is not thread-safe ! (but only in debug mode)
62  static DEBUG_MAP* creation = new DEBUG_MAP();
63  return *creation;
64  }
65 
66  static DEBUG_MAP& deletion__() {
67  // @warning This function is not thread-safe ! (but only in debug mode)
68  static DEBUG_MAP* deletion = new DEBUG_MAP();
69  return *deletion;
70  }
71 
72  std::string getFile__(const char* f) {
73  std::string s(f);
74  return s.erase(0, s.rfind("/") + 1);
75  }
76 
77  void show_trace__(const char* zeKey,
78  const char* zeFile,
79  long zeLine,
80  const char* zeMsg,
81  const void* zePtr) {
82 # ifdef GUM_DEEP_TRACE_ON
83  std::cerr << std::setw(40) << std::setfill(' ') << getFile__(zeFile) << "#"
84  << std::setfill('0') << std::setw(5) << std::dec << zeLine << " : "
85  << zeMsg << " <" << zeKey << "> [" << std::hex << zePtr << "]"
86  << std::dec << std::endl;
87 # endif // TRACE_CONSTRUCTION_ON
88  }
89 
90  void inc_creation__(const char* zeKey,
91  const char* zeFile,
92  long zeLine,
93  const char* zeMsg,
94  const void* zePtr,
95  int zeSize) {
96  debug_mutex.lock();
97  show_trace__(zeKey, zeFile, zeLine, zeMsg, zePtr);
98  creation__()[zeKey]++;
99  sizeof__()[zeKey] = zeSize;
100  debug_mutex.unlock();
101  }
102 
103  // to handle static element of agrum library
104  void dec_creation__(const char* zeKey,
105  const char* zeFile,
106  long zeLine,
107  const char* zeMsg,
108  const void* zePtr) {
109  debug_mutex.lock();
110  show_trace__(zeKey, zeFile, zeLine, zeMsg, zePtr);
111  creation__()[zeKey]--;
112  debug_mutex.unlock();
113  }
114 
115  void inc_deletion__(const char* zeKey,
116  const char* zeFile,
117  long zeLine,
118  const char* zeMsg,
119  const void* zePtr) {
120  debug_mutex.lock();
121  show_trace__(zeKey, zeFile, zeLine, zeMsg, zePtr);
122  deletion__()[zeKey]++;
123  debug_mutex.unlock();
124  }
125 
126  void dumpObjects__() {
127  Size nb_err = 0;
128  double total_size = 0.0;
129 
130  char fillChar = '_';
131  int widthColLibelle = 50;
132  int widthColSizeOf = 5;
133  int widthColItemsNumber = 8;
134 
135  std::cout << std::setfill('=') << "|" << std::setw(widthColLibelle + 2) << ""
136  << "|" << std::setw(widthColSizeOf + 4) << ""
137  << "|" << std::setw(widthColItemsNumber + 2) << ""
138  << "|" << std::setw(widthColItemsNumber + 2) << ""
139  << "|" << std::endl;
140  std::cout << std::setfill(' ') << "| " << std::left
141  << std::setw(widthColLibelle) << "Class Name" << std::right
142  << " | " << std::setw(widthColSizeOf) << "Size"
143  << " | " << std::setw(widthColItemsNumber) << "#Const"
144  << " | " << std::setw(widthColItemsNumber) << "#Dest"
145  << " |" << std::endl;
146  std::cout << std::setfill('-') << "|" << std::setw(widthColLibelle + 2) << ""
147  << "|" << std::setw(widthColSizeOf + 4) << ""
148  << "|" << std::setw(widthColItemsNumber + 2) << ""
149  << "|" << std::setw(widthColItemsNumber + 2) << ""
150  << "|" << std::endl;
151  // list of created objects
152  std::map< std::string, std::string > res;
153 
154  for (DEBUG_MAP::const_iterator xx = creation__().begin();
155  xx != creation__().end();
156  ++xx) {
157  std::stringstream stream;
158  int zeCreatedObjs = xx->second;
159  int zeDeletedObjts = -1;
160  int size = sizeof__()[xx->first];
161 
162  stream << std::setfill(fillChar = (fillChar == '_') ? ' ' : '_') << "| "
163  << std::setw(widthColLibelle) << std::left << xx->first << " | "
164  << std::right << std::setw(widthColSizeOf) << size << " o | "
165  << std::setw(widthColItemsNumber) << zeCreatedObjs << " | ";
166 
167  if (size > 0) total_size += zeCreatedObjs * (size / 1024.0);
168 
169  try {
170  zeDeletedObjts = deletion__()[xx->first];
171  stream << std::setfill(fillChar) << std::setw(widthColItemsNumber)
172  << zeDeletedObjts;
173  } catch (NotFound&) {
174  stream << std::setfill(fillChar) << std::setw(widthColItemsNumber)
175  << "?????";
176  }
177 
178  stream << " |";
179  ;
180 
181  if (zeCreatedObjs != zeDeletedObjts) {
182  nb_err += std::abs(zeDeletedObjts - zeCreatedObjs);
183  stream << "<--- failed";
184  }
185 
186  res.insert(make_pair(xx->first, stream.str()));
187  // res.push_back( stream.str() );
188  }
189 
190  // list of deleted objects, but not created (?)
191  for (DEBUG_MAP::const_iterator xx = deletion__().begin();
192  xx != deletion__().end();
193  ++xx) {
194  try {
195  creation__()[xx->first];
196  } catch (NotFound&) {
197  std::stringstream stream;
198  fillChar = (fillChar == '_') ? ' ' : '_';
199  stream << std::setfill(fillChar = (fillChar == '_') ? ' ' : '_') << "| "
200  << std::setw(widthColLibelle) << std::left << xx->first + " "
201  << " | " << std::right << std::setw(widthColSizeOf)
202  << sizeof__()[xx->first] << " o | "
203  << std::setw(widthColItemsNumber) << "?????"
204  << " | " << std::setw(widthColItemsNumber) << xx->second
205  << " |<--- failed";
206  res.insert(make_pair(xx->first, stream.str()));
207  // res.push_back( stream.str() );
208  nb_err += xx->second;
209  }
210  }
211 
212  for (const auto iter: res) {
213  std::cout << iter.second << std::endl;
214  }
215 
216  std::cout << std::setfill('-');
217 
218  std::cout << "|-" << std::setw(widthColLibelle) << ""
219  << "-|-" << std::setw(widthColSizeOf + 2) << ""
220  << "-|-" << std::setw(widthColItemsNumber) << ""
221  << "-|-" << std::setw(widthColItemsNumber) << ""
222  << "-|" << std::endl;
223 
224  std::cout << std::setfill(' ');
225 
226  if (nb_err == 0) {
227  std::cout << "| " << std::setw(widthColLibelle) << "NO MEMORY LEAK !"
228  << " | "
229  << std::setw(widthColSizeOf + widthColItemsNumber * 2 + 9) << ""
230  << "|" << std::endl;
231  } else {
232  std::cout << "| " << std::setw(widthColLibelle) << "Memory leaks found "
233  << ""
234  << " | "
235  << std::setw(widthColSizeOf + widthColItemsNumber * 2 - 6)
236  << nb_err << " object(s) "
237  << "|" << std::endl;
238  }
239 
240  std::cout << "| " << std::setw(widthColLibelle) << "total "
241  << " | " << std::fixed
242  << std::setw(widthColSizeOf + widthColItemsNumber * 2 - 4)
243  << std::setprecision(2) << total_size << " Ko "
244  << "|" << std::endl;
245 
246  std::cout << std::setfill('=') << "|" << std::setw(widthColLibelle + 2) << ""
247  << "|" << std::setw(widthColSizeOf + widthColItemsNumber * 2 + 10)
248  << ""
249  << "|" << std::endl;
250  }
251 
252  // take into account static objects in agrum (no called destructor before
253  // exit())
254  void staticCorrections__() {}
255 
256  void atexit__() {
257  staticCorrections__();
258  dumpObjects__();
259  creation__().clear();
260  deletion__().clear();
261  }
262 
263  } // namespace __debug__
264 
265 # endif // GUM_DEBUG_MODE
266 
267 } /* namespace gum */
268 
269 #endif // DOXYGEN_SHOULD_SKIP_THIS