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