Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
berryDebugUtil.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 #include "berryDebugUtil.h"
16 #include "berryObject.h"
17 #include "berryLog.h"
18 #include "berryPlatform.h"
20 
21 #include "internal/berryCTKPluginActivator.h"
22 
23 #include <QDir>
24 #include <QDebug>
25 
26 #include <Poco/Bugcheck.h>
27 #include <Poco/NumberParser.h>
28 #include <Poco/DOM/NodeList.h>
29 #include <Poco/DOM/DOMParser.h>
30 #include <Poco/DOM/Document.h>
31 #include <Poco/DOM/Element.h>
32 #include <Poco/DOM/DOMWriter.h>
33 #include <Poco/SAX/InputSource.h>
34 #include <Poco/SAX/SAXException.h>
35 
36 #include <Poco/FileStream.h>
37 
38 #include <sstream>
39 
40 #include <numeric>
41 
42 namespace berry
43 {
44 
46 
47 const QString DebugUtil::DEBUG_UTIL_XML = "debugutil.xml";
48 const QString DebugUtil::DEBUGUTIL_TAG = "debugutil";
49 const QString DebugUtil::TRACEOBJECT_TAG = "traceObject";
50 const QString DebugUtil::TRACECLASS_TAG = "traceClass";
51 const QString DebugUtil::ID_ATTR = "id";
52 const QString DebugUtil::NAME_ATTR = "name";
53 
54 QHash<quint32, QList<unsigned int> > DebugUtil::m_TraceIdToSmartPointerMap;
55 QHash<quint32, const Object*> DebugUtil::m_TraceIdToObjectMap;
56 QSet<unsigned int> DebugUtil::m_TracedObjects;
57 QSet<QString> DebugUtil::m_TracedClasses;
58 
59 class NotClassName: public std::unary_function<const Object*, bool>
60 {
61 
62  QString name;
63 
64 public:
65  NotClassName(const QString& s) :
66  name(s)
67  {
68  }
69  bool operator()(const Object* entry) const
70  {
71  return name != entry->GetClassName();
72  }
73 };
74 
76 {
77  static DebugBreakpointManager breakpointManager;
78  return &breakpointManager;
79 }
80 
81 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
82 void DebugUtil::TraceObject(const Object* object)
83 {
84  BERRY_INFO << "Tracing enabled for: " << object->GetTraceId() << std::endl;
85  m_TracedObjects.insert(object->GetTraceId());
86  _G_ObjectEvents.objTracingEvent(object->GetTraceId(), true, object);
87 }
88 #else
89 void DebugUtil::TraceObject(const Object* /*object*/)
90 {
91 }
92 #endif
93 
94 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
95 void DebugUtil::TraceObject(unsigned int traceId)
96 {
97  BERRY_INFO << "Tracing enabled for: " << traceId << std::endl;
98  m_TracedObjects.insert(traceId);
99  TraceIdToObjectType::ConstIterator i = m_TraceIdToObjectMap.find(traceId);
100  if (i != m_TraceIdToObjectMap.end())
101  _G_ObjectEvents.objTracingEvent(traceId, true, i.value());
102  else
103  _G_ObjectEvents.objTracingEvent(traceId, true, 0);
104 }
105 #else
106 void DebugUtil::TraceObject(unsigned int /*traceId*/)
107 {
108 }
109 #endif
110 
111 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
112 void DebugUtil::TraceClass(const QString& className)
113 {
114  BERRY_INFO << "Tracing enabled for: " << className << std::endl;
115  m_TracedClasses.insert(className);
116  //_G_ObjectEvents.objTracingEvent(object->GetTraceId(), true, object);
117 }
118 #else
119 void DebugUtil::TraceClass(const QString& /*className*/)
120 {
121 }
122 #endif
123 
124 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
125 void DebugUtil::StopTracing(unsigned int traceId)
126 {
127 
128  BERRY_INFO << "Tracing stopped for: " << traceId << std::endl;
129  m_TracedObjects.remove(traceId);
130  TraceIdToObjectType::ConstIterator i = m_TraceIdToObjectMap.find(traceId);
131  if (i != m_TraceIdToObjectMap.end())
132  _G_ObjectEvents.objTracingEvent(traceId, false, i.value());
133  else
134  _G_ObjectEvents.objTracingEvent(traceId, false, 0);
135 }
136 #else
137 void DebugUtil::StopTracing(unsigned int /*traceId*/)
138 {
139 }
140 #endif
141 
142 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
143 void DebugUtil::StopTracing(const Object* obj)
144 {
145  BERRY_INFO << "Tracing stopped for: " << obj->GetTraceId() << std::endl;
146  m_TracedObjects.remove(obj->GetTraceId());
147  _G_ObjectEvents.objTracingEvent(obj->GetTraceId(), false, obj);
148 }
149 #else
150 void DebugUtil::StopTracing(const Object* /*obj*/)
151 {
152 }
153 #endif
154 
155 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
156 void DebugUtil::StopTracing(const QString& className)
157 {
158  BERRY_INFO << "Tracing stopped for: " << className << std::endl;
159  m_TracedClasses.remove(className);
160  //_G_ObjectEvents.objTracingEvent(obj->GetTraceId(), false, obj);
161 }
162 #else
163 void DebugUtil::StopTracing(const QString& /*className*/)
164 {
165 }
166 #endif
167 
168 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
169 bool DebugUtil::IsTraced(const Object* object)
170 {
171  if (m_TracedObjects.find(object->GetTraceId()) != m_TracedObjects.end())
172  return true;
173 
174  if (m_TracedClasses.find(object->GetClassName()) != m_TracedClasses.end())
175  return true;
176 
177  return false;
178 }
179 #else
180 bool DebugUtil::IsTraced(const Object* /*object*/)
181 {
182  return false;
183 }
184 #endif
185 
186 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
187 bool DebugUtil::IsTraced(unsigned int traceId)
188 {
189  if (m_TracedObjects.find(traceId) != m_TracedObjects.end())
190  return true;
191 
192  TraceIdToObjectType::Iterator it = m_TraceIdToObjectMap.find(traceId);
193  if (it != m_TraceIdToObjectMap.end())
194  {
195  if (m_TracedClasses.find(it.value()->GetClassName()) != m_TracedClasses.end())
196  return true;
197  }
198 
199  return false;
200 }
201 #else
202 bool DebugUtil::IsTraced(unsigned int /*traceId*/)
203 {
204  return false;
205 }
206 #endif
207 
208 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
209 bool DebugUtil::IsTraced(const QString& className)
210 {
211  return m_TracedClasses.find(className) != m_TracedClasses.end();
212 }
213 #else
214 bool DebugUtil::IsTraced(const QString& /*className*/)
215 {
216  return false;
217 }
218 #endif
219 
220 QSet<unsigned int> DebugUtil::GetTracedObjects()
221 {
222  return m_TracedObjects;
223 }
224 
225 const Object* DebugUtil::GetObject(unsigned int traceId)
226 {
227  return m_TraceIdToObjectMap[traceId];
228 }
229 
230 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
231 QList<unsigned int> DebugUtil::GetSmartPointerIDs(
232  const Object* objectPointer, const QList<unsigned int>& excludeList)
233 {
234  Q_ASSERT(objectPointer != 0);
235  QList<unsigned int> ids = m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()];
236  for (QList<unsigned int>::const_iterator iter = excludeList.begin();
237  iter != excludeList.end(); ++iter)
238  ids.removeAll(*iter);
239  return ids;
240 }
241 #else
242 QList<unsigned int> DebugUtil::GetSmartPointerIDs(
243  const Object* /*objectPointer*/, const QList<unsigned int>& /*excludeList*/)
244 {
245  return QList<unsigned int>();
246 }
247 #endif
248 
249 QList<const Object*> DebugUtil::GetRegisteredObjects()
250 {
251  return m_TraceIdToObjectMap.values();
252 }
253 
254 void DebugUtil::PrintSmartPointerIDs(const Object* objectPointer, const QList<unsigned int>& excludeList)
255 {
256  qDebug() << "SmartPointer IDs [ ";
257  if (IsTraced(objectPointer))
258  {
259  QList<unsigned int> ids = GetSmartPointerIDs(objectPointer, excludeList);
260  for (QList<unsigned int>::const_iterator iter = ids.begin();
261  iter != ids.end(); ++iter)
262  {
263  qDebug() << *iter << " ";
264  }
265  }
266  else
267  {
268  qDebug() << "n/a ";
269  }
270  qDebug() << "]\n";
271 }
272 
274 {
275  _G_ObjectEvents.AddListener(listener);
276 }
277 
279 {
280  _G_ObjectEvents.RemoveListener(listener);
281 }
282 
284 {
285  m_TraceIdToObjectMap.clear();
286  m_TraceIdToSmartPointerMap.clear();
287  m_TracedObjects.clear();
288 }
289 
291 {
292  QSet<QString> names;
293 
294  for (auto object : m_TraceIdToObjectMap)
295  names.insert(object->GetClassName());
296 
297  if (!names.isEmpty())
298  {
299  std::cout << std::endl << std::endl << "#########################################################" << std::endl;
300  std::cout << "######## berry::Object leakage summary: ########" << std::endl << std::endl;
301 
302  for (QSet<QString>::const_iterator i = names.begin();
303  i != names.end(); ++i)
304  {
305  PrintObjectSummary(*i, details);
306  if (details) std::cout << std::endl;
307  }
308 
309  std::cout << std::endl << "#########################################################" << std::endl << std::endl;
310  }
311 
312  return !names.isEmpty();
313 }
314 
315 bool DebugUtil::PrintObjectSummary(const QString& className, bool details)
316 {
317  TraceIdToObjectType::ConstIterator endIter =
318  std::remove_if(m_TraceIdToObjectMap.begin(), m_TraceIdToObjectMap.end(), NotClassName(className));
319 
320  qDebug() << "Class:" << className;
321  if (details) std::cout << std::endl;
322 
323  std::size_t count = 0;
324  for (TraceIdToObjectType::ConstIterator iter = m_TraceIdToObjectMap.begin();
325  iter != endIter; ++iter, ++count)
326  {
327  if (details)
328  {
329  qDebug() << (*(iter.value()));
330  PrintSmartPointerIDs(iter.value());
331  }
332  }
333  qDebug() << "(" << count << " instances)\n";
334  return (count!=0);
335 }
336 
338 {
339  static unsigned int counter = 0;
340  return counter;
341 }
342 
343 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
344 void DebugUtil::UnregisterSmartPointer(unsigned int smartPointerId, const Object* objectPointer)
345 {
346  poco_assert(objectPointer != 0);
347 
348  m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()].removeAll(smartPointerId);
349  _G_ObjectEvents.spDestroyedEvent(smartPointerId, objectPointer);
350 }
351 #else
352 void DebugUtil::UnregisterSmartPointer(unsigned int /*smartPointerId*/, const Object* /*objectPointer*/)
353 {
354 }
355 #endif
356 
357 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
358 void DebugUtil::RegisterSmartPointer(unsigned int smartPointerId, const Object* objectPointer, bool /*recordStack*/)
359 {
360  poco_assert(objectPointer != 0);
361 
362  if (m_TracedClasses.find(objectPointer->GetClassName()) != m_TracedClasses.end() ||
363  m_TracedObjects.find(objectPointer->GetTraceId()) != m_TracedObjects.end())
364  {
365  m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()].push_back(smartPointerId);
366  _G_ObjectEvents.spCreatedEvent(smartPointerId, objectPointer);
367  }
368 
369  if (GetBreakpointManager()->BreakAtSmartpointer(smartPointerId))
370  poco_debugger_msg("SmartPointer Breakpoint reached");
371 }
372 #else
373 void DebugUtil::RegisterSmartPointer(unsigned int /*smartPointerId*/, const Object* /*objectPointer*/, bool /*recordStack*/)
374 {
375 }
376 #endif
377 
378 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
379 void DebugUtil::RegisterObject(const Object* objectPointer)
380 {
381  m_TraceIdToObjectMap.insert(objectPointer->GetTraceId(), objectPointer);
382  _G_ObjectEvents.objCreatedEvent(objectPointer);
383 
384  if (GetBreakpointManager()->BreakAtObject(objectPointer->GetTraceId()))
385  {
386  std::string msg = "SmartPointer Breakpoint reached for ";
387  msg += objectPointer->GetClassName().toStdString();
388  poco_debugger_msg(msg.c_str());
389  }
390 }
391 #else
392 void DebugUtil::RegisterObject(const Object* /*objectPointer*/)
393 {
394 }
395 #endif
396 
397 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
398 void DebugUtil::UnregisterObject(const Object* objectPointer)
399 {
400  m_TraceIdToObjectMap.remove(objectPointer->GetTraceId());
401  _G_ObjectEvents.objDestroyedEvent(objectPointer);
402 }
403 #else
404 void DebugUtil::UnregisterObject(const Object* /*objectPointer*/)
405 {
406 }
407 #endif
408 
409 bool DebugUtil::GetPersistencePath(QDir& path)
410 {
411  QFileInfo statePath = CTKPluginActivator::getPluginContext()->getDataFile(QString());
412  path = statePath.absoluteFilePath();
413  return true;
414 }
415 
416 void DebugUtil::SaveState(const QDir& path)
417 {
418  QString saveFile = path.absoluteFilePath(DEBUG_UTIL_XML);
419 
420  auto doc = new Poco::XML::Document();
421  Poco::XML::Element* debugutil = doc->createElement(DEBUGUTIL_TAG.toStdString());
422  doc->appendChild(debugutil)->release();
423 
424  for (QSet<unsigned int>::const_iterator i = m_TracedObjects.begin();
425  i != m_TracedObjects.end(); ++i)
426  {
427  Poco::XML::Element* traceObject = doc->createElement(TRACEOBJECT_TAG.toStdString());
428  debugutil->appendChild(traceObject)->release();
429  traceObject->setAttribute(ID_ATTR.toStdString(), QString::number(*i).toStdString());
430  }
431 
432  for (QSet<QString>::const_iterator i = m_TracedClasses.begin();
433  i != m_TracedClasses.end(); ++i)
434  {
435  Poco::XML::Element* traceClass = doc->createElement(TRACECLASS_TAG.toStdString());
436  debugutil->appendChild(traceClass)->release();
437  traceClass->setAttribute(NAME_ATTR.toStdString(), i->toStdString());
438  }
439 
440  try
441  {
442  Poco::FileOutputStream writer(saveFile.toStdString());
443  Poco::XML::DOMWriter out;
444  out.setOptions(3); //write declaration and pretty print
445  out.writeNode(writer, doc);
446 
447  doc->release();
448 
449  // save BreakpointManager
450  QString saveBM = path.absoluteFilePath(QString::fromStdString(DebugBreakpointManager::BREAKPOINTS_XML));
451  GetBreakpointManager()->SaveState(saveBM);
452  }
453  catch (Poco::FileException& e)
454  {
455  BERRY_WARN << e.displayText();
456  }
457 
458 }
459 
460 void DebugUtil::RestoreState(const QDir& path)
461 {
462  QString restoreFile = path.absoluteFilePath(DEBUG_UTIL_XML);
463 
464  try
465  {
466  Poco::XML::DOMParser parser;
467 
468  Poco::FileInputStream reader(restoreFile.toStdString());
469  Poco::XML::InputSource source(reader);
470 
471  //source.setSystemId(baseDir);
472  Poco::XML::Document* doc = parser.parse(&source);
473  Poco::XML::Element* debugutil = doc->documentElement();
474 
475  if (debugutil)
476  {
477  // restore traced objects
478  Poco::XML::NodeList* elementList = debugutil->getElementsByTagName(TRACEOBJECT_TAG.toStdString());
479  for (std::size_t i = 0; i < elementList->length(); i++)
480  {
481  Poco::XML::Element* elem =
482  dynamic_cast<Poco::XML::Element*> (elementList->item(static_cast<unsigned long>(i)));
483 
484  if (!elem->hasAttribute(ID_ATTR.toStdString())) continue;
485 
486  const std::string& attr = elem->getAttribute(ID_ATTR.toStdString());
487 
488  int traceId = 0;
489  try
490  {
491  traceId = Poco::NumberParser::parse(attr);
492  }
493  catch (const Poco::SyntaxException& e)
494  {
495  BERRY_WARN << e.displayText();
496  }
497 
498  DebugUtil::TraceObject(traceId);
499  }
500  elementList->release();
501 
502  // restore traced classes
503  elementList = debugutil->getElementsByTagName(TRACECLASS_TAG.toStdString());
504  for (std::size_t i = 0; i < elementList->length(); i++)
505  {
506  Poco::XML::Element* elem =
507  dynamic_cast<Poco::XML::Element*> (elementList->item(static_cast<unsigned long>(i)));
508 
509  if (!elem->hasAttribute(NAME_ATTR.toStdString())) continue;
510 
511  const std::string& traceClass = elem->getAttribute(NAME_ATTR.toStdString());
512  if (!traceClass.empty())
513  DebugUtil::TraceClass(QString::fromStdString(traceClass));
514  }
515  elementList->release();
516  }
517 
518  doc->release();
519  }
520  catch (Poco::XML::SAXParseException& e)
521  {
522  BERRY_WARN << e.displayText();
523  }
524  catch (Poco::FileNotFoundException&)
525  {
526 
527  }
528  catch (Poco::FileException& e)
529  {
530  BERRY_WARN << e.displayText();
531  }
532 
533  // restore BreakpointManager
534  GetBreakpointManager()->RestoreState(path.absoluteFilePath(QString::fromStdString(DebugBreakpointManager::BREAKPOINTS_XML)));
535 }
536 
537 }
virtual QString GetClassName() const
Definition: berryObject.cpp:71
static void RemoveObjectListener(IDebugObjectListener *listener)
static void UnregisterSmartPointer(unsigned int smartPointerId, const Object *objectPointer)
Light weight base class for most BlueBerry classes.
Definition: berryObject.h:72
void AddListener(IDebugObjectListener *listener)
static const Object * GetObject(unsigned int traceId)
static void TraceClass(const QString &className)
static QList< unsigned int > GetSmartPointerIDs(const Object *objectPointer, const QList< unsigned int > &excludeList=QList< unsigned int >())
static unsigned int & GetSmartPointerCounter()
static void RestoreState(const QDir &path)
static void ResetObjectSummary()
static IDebugObjectListener::Events _G_ObjectEvents
#define BERRY_INFO
Definition: berryLog.h:20
static const std::string BREAKPOINTS_XML
static void RegisterSmartPointer(unsigned int smartPointerId, const Object *objectPointer, bool recordStack=false)
static QSet< unsigned int > GetTracedObjects()
static bool IsTraced(const Object *object)
static void RegisterObject(const Object *objectPointer)
#define BERRY_WARN
Definition: berryLog.h:21
static bool PrintObjectSummary(bool details=false)
static DebugBreakpointManager * GetBreakpointManager()
static void PrintSmartPointerIDs(const Object *objectPointer, const QList< unsigned int > &excludeList=QList< unsigned int >())
static QList< const Object * > GetRegisteredObjects()
static void AddObjectListener(IDebugObjectListener *listener)
static void SaveState(const QDir &path)
void RemoveListener(IDebugObjectListener *listener)
static void StopTracing(unsigned int traceId)
static void TraceObject(const Object *)
static void UnregisterObject(const Object *objectPointer)