aGrUM  0.21.0
a C++ library for (probabilistic) graphical models
debug.cpp
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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 << " : " << zeMsg << " <"
85  << zeKey << "> [" << std::hex << zePtr << "]" << std::dec << std::endl;
86 # endif // TRACE_CONSTRUCTION_ON
87  }
88 
89  void _inc_creation_(const char* zeKey,
90  const char* zeFile,
91  long zeLine,
92  const char* zeMsg,
93  const void* zePtr,
94  int zeSize) {
95  debug_mutex.lock();
96  _show_trace_(zeKey, zeFile, zeLine, zeMsg, zePtr);
97  _creation_()[zeKey]++;
98  _sizeof_()[zeKey] = zeSize;
99  debug_mutex.unlock();
100  }
101 
102  // to handle static element of agrum library
103  void _dec_creation_(const char* zeKey,
104  const char* zeFile,
105  long zeLine,
106  const char* zeMsg,
107  const void* zePtr) {
108  debug_mutex.lock();
109  _show_trace_(zeKey, zeFile, zeLine, zeMsg, zePtr);
110  _creation_()[zeKey]--;
111  debug_mutex.unlock();
112  }
113 
114  void _inc_deletion_(const char* zeKey,
115  const char* zeFile,
116  long zeLine,
117  const char* zeMsg,
118  const void* zePtr) {
119  debug_mutex.lock();
120  _show_trace_(zeKey, zeFile, zeLine, zeMsg, zePtr);
121  _deletion_()[zeKey]++;
122  debug_mutex.unlock();
123  }
124 
125  void _dumpObjects_() {
126  Size nb_err = 0;
127  double total_size = 0.0;
128 
129  char fillChar = '_';
130  int widthColLibelle = 50;
131  int widthColSizeOf = 5;
132  int widthColItemsNumber = 8;
133 
134  std::cout << std::setfill('=') << "|" << std::setw(widthColLibelle + 2) << ""
135  << "|" << std::setw(widthColSizeOf + 4) << ""
136  << "|" << std::setw(widthColItemsNumber + 2) << ""
137  << "|" << std::setw(widthColItemsNumber + 2) << ""
138  << "|" << std::endl;
139  std::cout << std::setfill(' ') << "| " << std::left << std::setw(widthColLibelle)
140  << "Class Name" << std::right << " | " << 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(); xx != _creation_().end(); ++xx) {
153  std::stringstream stream;
154  int zeCreatedObjs = xx->second;
155  int zeDeletedObjts = -1;
156  int size = _sizeof_()[xx->first];
157 
158  stream << std::setfill(fillChar = (fillChar == '_') ? ' ' : '_') << "| "
159  << std::setw(widthColLibelle) << std::left << xx->first << " | " << std::right
160  << std::setw(widthColSizeOf) << size << " o | " << std::setw(widthColItemsNumber)
161  << zeCreatedObjs << " | ";
162 
163  if (size > 0) total_size += zeCreatedObjs * (size / 1024.0);
164 
165  try {
166  zeDeletedObjts = _deletion_()[xx->first];
167  stream << std::setfill(fillChar) << std::setw(widthColItemsNumber) << zeDeletedObjts;
168  } catch (NotFound&) {
169  stream << std::setfill(fillChar) << std::setw(widthColItemsNumber) << "?????";
170  }
171 
172  stream << " |";
173  ;
174 
175  if (zeCreatedObjs != zeDeletedObjts) {
176  nb_err += std::abs(zeDeletedObjts - zeCreatedObjs);
177  stream << "<--- failed";
178  }
179 
180  res.insert(make_pair(xx->first, stream.str()));
181  // res.push_back( stream.str() );
182  }
183 
184  // list of deleted objects, but not created (?)
185  for (DEBUG_MAP::const_iterator xx = _deletion_().begin(); xx != _deletion_().end(); ++xx) {
186  try {
187  _creation_()[xx->first];
188  } catch (NotFound&) {
189  std::stringstream stream;
190  fillChar = (fillChar == '_') ? ' ' : '_';
191  stream << std::setfill(fillChar = (fillChar == '_') ? ' ' : '_') << "| "
192  << std::setw(widthColLibelle) << std::left << xx->first + " "
193  << " | " << std::right << std::setw(widthColSizeOf) << _sizeof_()[xx->first]
194  << " o | " << std::setw(widthColItemsNumber) << "?????"
195  << " | " << std::setw(widthColItemsNumber) << xx->second << " |<--- failed";
196  res.insert(make_pair(xx->first, stream.str()));
197  // res.push_back( stream.str() );
198  nb_err += xx->second;
199  }
200  }
201 
202  for (const auto iter: res) {
203  std::cout << iter.second << std::endl;
204  }
205 
206  std::cout << std::setfill('-');
207 
208  std::cout << "|-" << std::setw(widthColLibelle) << ""
209  << "-|-" << std::setw(widthColSizeOf + 2) << ""
210  << "-|-" << std::setw(widthColItemsNumber) << ""
211  << "-|-" << std::setw(widthColItemsNumber) << ""
212  << "-|" << std::endl;
213 
214  std::cout << std::setfill(' ');
215 
216  if (nb_err == 0) {
217  std::cout << "| " << std::setw(widthColLibelle) << "NO MEMORY LEAK !"
218  << " | " << std::setw(widthColSizeOf + widthColItemsNumber * 2 + 9) << ""
219  << "|" << std::endl;
220  } else {
221  std::cout << "| " << std::setw(widthColLibelle) << "Memory leaks found "
222  << ""
223  << " | " << std::setw(widthColSizeOf + widthColItemsNumber * 2 - 6) << nb_err
224  << " object(s) "
225  << "|" << std::endl;
226  }
227 
228  std::cout << "| " << std::setw(widthColLibelle) << "total "
229  << " | " << std::fixed << std::setw(widthColSizeOf + widthColItemsNumber * 2 - 4)
230  << std::setprecision(2) << total_size << " Ko "
231  << "|" << std::endl;
232 
233  std::cout << std::setfill('=') << "|" << std::setw(widthColLibelle + 2) << ""
234  << "|" << std::setw(widthColSizeOf + widthColItemsNumber * 2 + 10) << ""
235  << "|" << std::endl;
236  }
237 
238  // take into account static objects in agrum (no called destructor before
239  // exit())
240  void _staticCorrections_() {}
241 
242  void _atexit_() {
243  _staticCorrections_();
244  _dumpObjects_();
245  _creation_().clear();
246  _deletion_().clear();
247  }
248 
249  } // namespace __debug__
250 
251 # endif // GUM_DEBUG_MODE
252 
253 } /* namespace gum */
254 
255 #endif // DOXYGEN_SHOULD_SKIP_THIS