aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
debug.cpp
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41
48
49#include <algorithm>
50#include <iomanip>
51#include <iostream>
52#include <mutex>
53#include <string>
54#include <vector>
55
56#include <agrum/agrum.h>
57
58#ifndef DOXYGEN_SHOULD_SKIP_THIS
59
60# include <map>
61
62namespace gum {
63
64# ifdef GUM_DEBUG_MODE
65
66 namespace __debug__ {
67 using DEBUG_MAP = std::map< std::string, int >;
68
69 static std::mutex& _debug_mutex_() {
70 // Here, this initialization is thread-safe due to Meyer’s Singleton property
71 static std::mutex debug_mutex;
72 return debug_mutex;
73 }
74
75 // this static hashtable only on debug mode.
76 static DEBUG_MAP& _sizeof_() {
77 // Here, this initialization is thread-safe due to Meyer’s Singleton property
78 static DEBUG_MAP sizeOf;
79 return sizeOf;
80 }
81
82 // this static hashtable only on debug mode.
83 static DEBUG_MAP& _creation_() {
84 // Here, this initialization is thread-safe due to Meyer’s Singleton property
85 static DEBUG_MAP creation;
86 return creation;
87 }
88
89 static DEBUG_MAP& _deletion_() {
90 // Here, this initialization is thread-safe due to Meyer’s Singleton property
91 static DEBUG_MAP deletion;
92 return deletion;
93 }
94
95 std::string _getFile_(const char* f) {
96 std::string s(f);
97 return s.erase(0, s.rfind('/') + 1);
98 }
99
100 void _show_trace_(const char* zeKey,
101 const char* zeFile,
102 long zeLine,
103 const char* zeMsg,
104 const void* zePtr) {
105# ifdef GUM_DEEP_TRACE_ON
106 std::cerr << std::setw(40) << std::setfill(' ') << _getFile_(zeFile) << "#"
107 << std::setfill('0') << std::setw(5) << std::dec << zeLine << " : " << zeMsg << " <"
108 << zeKey << "> [" << std::hex << zePtr << "]" << std::dec << std::endl;
109# endif // TRACE_CONSTRUCTION_ON
110 }
111
112 void _inc_creation_(const char* zeKey,
113 const char* zeFile,
114 long zeLine,
115 const char* zeMsg,
116 const void* zePtr,
117 int zeSize) {
118 static DEBUG_MAP& creation = _creation_();
119 static DEBUG_MAP& size = _sizeof_();
120 std::unique_lock lck{_debug_mutex_()};
121
122 _show_trace_(zeKey, zeFile, zeLine, zeMsg, zePtr);
123 creation[zeKey]++;
124 size[zeKey] = zeSize;
125 }
126
127 // to handle static element of agrum library
128 void _dec_creation_(const char* zeKey,
129 const char* zeFile,
130 long zeLine,
131 const char* zeMsg,
132 const void* zePtr) {
133 static DEBUG_MAP& creation = _creation_();
134 std::unique_lock lck{_debug_mutex_()};
135
136 _show_trace_(zeKey, zeFile, zeLine, zeMsg, zePtr);
137 creation[zeKey]--;
138 }
139
140 void _inc_deletion_(const char* zeKey,
141 const char* zeFile,
142 long zeLine,
143 const char* zeMsg,
144 const void* zePtr) {
145 static DEBUG_MAP& deletion = _deletion_();
146 std::unique_lock lck{_debug_mutex_()};
147
148 _show_trace_(zeKey, zeFile, zeLine, zeMsg, zePtr);
149 deletion[zeKey]++;
150 }
151
152 void _dumpObjects_() {
153 DEBUG_MAP& creation = _creation_();
154 DEBUG_MAP& deletion = _deletion_();
155 DEBUG_MAP& sizeOf = _sizeof_();
156
157 Size nb_err = 0;
158 double total_size = 0.0;
159
160 char fillChar = '_';
161 int widthColLibelle = 50;
162 int widthColSizeOf = 5;
163 int widthColItemsNumber = 8;
164
165 std::cout << std::setfill('=') << "|" << std::setw(widthColLibelle + 2) << ""
166 << "|" << std::setw(widthColSizeOf + 4) << ""
167 << "|" << std::setw(widthColItemsNumber + 2) << ""
168 << "|" << std::setw(widthColItemsNumber + 2) << ""
169 << "|" << std::endl;
170 std::cout << std::setfill(' ') << "| " << std::left << std::setw(widthColLibelle)
171 << "Class Name" << std::right << " | " << std::setw(widthColSizeOf) << "Size"
172 << " | " << std::setw(widthColItemsNumber) << "#Const"
173 << " | " << std::setw(widthColItemsNumber) << "#Dest"
174 << " |" << std::endl;
175 std::cout << std::setfill('-') << "|" << std::setw(widthColLibelle + 2) << ""
176 << "|" << std::setw(widthColSizeOf + 4) << ""
177 << "|" << std::setw(widthColItemsNumber + 2) << ""
178 << "|" << std::setw(widthColItemsNumber + 2) << ""
179 << "|" << std::endl;
180 // list of created objects
181 std::map< std::string, std::string > res;
182
183 for (DEBUG_MAP::const_iterator xx = creation.begin(); xx != creation.end(); ++xx) {
184 std::stringstream stream;
185 int zeCreatedObjs = xx->second;
186 int zeDeletedObjts = -1;
187 int size = sizeOf[xx->first];
188
189 stream << std::setfill(fillChar = (fillChar == '_') ? ' ' : '_') << "| "
190 << std::setw(widthColLibelle) << std::left << xx->first << " | " << std::right
191 << std::setw(widthColSizeOf) << size << " o | " << std::setw(widthColItemsNumber)
192 << zeCreatedObjs << " | ";
193
194 if (size > 0) total_size += zeCreatedObjs * (size / 1024.0);
195
196 try {
197 zeDeletedObjts = deletion[xx->first];
198 stream << std::setfill(fillChar) << std::setw(widthColItemsNumber) << zeDeletedObjts;
199 } catch (NotFound const&) {
200 stream << std::setfill(fillChar) << std::setw(widthColItemsNumber) << "?????";
201 }
202
203 stream << " |";
204
205 if (zeCreatedObjs != zeDeletedObjts) {
206 nb_err += std::abs(zeDeletedObjts - zeCreatedObjs);
207 stream << "<--- failed";
208 }
209
210 res.insert(make_pair(xx->first, stream.str()));
211 }
212
213 // list of deleted objects, but not created (?)
214 for (DEBUG_MAP::const_iterator xx = deletion.begin(); xx != deletion.end(); ++xx) {
215 try {
216 creation[xx->first];
217 } catch (NotFound const&) {
218 std::stringstream stream;
219 fillChar = (fillChar == '_') ? ' ' : '_';
220 stream << std::setfill(fillChar = (fillChar == '_') ? ' ' : '_') << "| "
221 << std::setw(widthColLibelle) << std::left << xx->first + " " << " | "
222 << std::right << std::setw(widthColSizeOf) << sizeOf[xx->first] << " o | "
223 << std::setw(widthColItemsNumber) << "?????"
224 << " | " << std::setw(widthColItemsNumber) << xx->second << " |<--- failed";
225 res.insert(make_pair(xx->first, stream.str()));
226
227 nb_err += xx->second;
228 }
229 }
230
231 for (const auto& [fisrt, second]: res)
232 std::cout << second << std::endl;
233
234
235 std::cout << std::setfill('-');
236
237 std::cout << "|-" << std::setw(widthColLibelle) << ""
238 << "-|-" << std::setw(widthColSizeOf + 2) << ""
239 << "-|-" << std::setw(widthColItemsNumber) << ""
240 << "-|-" << std::setw(widthColItemsNumber) << ""
241 << "-|" << std::endl;
242
243 std::cout << std::setfill(' ');
244
245 if (nb_err == 0) {
246 std::cout << "| " << std::setw(widthColLibelle) << "NO MEMORY LEAK !"
247 << " | " << std::setw(widthColSizeOf + widthColItemsNumber * 2 + 9) << ""
248 << "|" << std::endl;
249 } else {
250 std::cout << "| " << std::setw(widthColLibelle) << "Memory leaks found "
251 << ""
252 << " | " << std::setw(widthColSizeOf + widthColItemsNumber * 2 - 6) << nb_err
253 << " object(s) "
254 << "|" << std::endl;
255 }
256
257 std::cout << "| " << std::setw(widthColLibelle) << "total "
258 << " | " << std::fixed << std::setw(widthColSizeOf + widthColItemsNumber * 2 - 4)
259 << std::setprecision(2) << total_size << " Ko "
260 << "|" << std::endl;
261
262 std::cout << std::setfill('=') << "|" << std::setw(widthColLibelle + 2) << ""
263 << "|" << std::setw(widthColSizeOf + widthColItemsNumber * 2 + 10) << ""
264 << "|" << std::endl;
265 }
266
267 // take into account static objects in agrum (no called destructor before
268 // exit())
269 void _staticCorrections_() {
271 _inc_deletion_("HashTable", "GraphElements.cpp", 40, "destructor of", nullptr);
272 _inc_deletion_("Set", "GraphElements.cpp", 40, "destructor of", nullptr);
273 }
274
275 void _atexit_() {
276 _staticCorrections_();
277 _dumpObjects_();
278 _creation_().clear();
279 _deletion_().clear();
280 }
281
282 } // namespace __debug__
283
284# endif // GUM_DEBUG_MODE
285
286} /* namespace gum */
287
288#endif // DOXYGEN_SHOULD_SKIP_THIS
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
void _atexit_()
Used for debug purpose.
Internal namespace for aGrUM debugging tools.
Definition agrum.h:52
gum is the global namespace for all aGrUM entities
Definition agrum.h:46