Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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)