MIRA
Profiler.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Contact: info@mira-project.org
9  *
10  * Commercial Usage:
11  * Licensees holding valid commercial licenses may use this file in
12  * accordance with the commercial license agreement provided with the
13  * software or, alternatively, in accordance with the terms contained in
14  * a written agreement between you and MLAB or NICR.
15  *
16  * GNU General Public License Usage:
17  * Alternatively, this file may be used under the terms of the GNU
18  * General Public License version 3.0 as published by the Free Software
19  * Foundation and appearing in the file LICENSE.GPL3 included in the
20  * packaging of this file. Please review the following information to
21  * ensure the GNU General Public License version 3.0 requirements will be
22  * met: http://www.gnu.org/copyleft/gpl.html.
23  * Alternatively you may (at your option) use any later version of the GNU
24  * General Public License if such license has been publicly approved by
25  * MLAB and NICR (or its successors, if any).
26  *
27  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
28  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
29  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
30  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
33  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
35  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
36  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
37  */
38 
47 #ifndef _MIRA_PROFILER_H_
48 #define _MIRA_PROFILER_H_
49 
50 #ifdef _MSC_VER // Microsoft Visual C++
51  #include <intrin.h> // for rdtsc intrinsic
52  #pragma intrinsic(__rdtsc)
53 #endif
54 
55 #include <string>
56 #include <map>
57 
58 #ifndef Q_MOC_RUN
59 #include <boost/optional.hpp>
60 #endif
61 
62 #include <thread/Thread.h>
63 #include <thread/Spinlock.h>
64 #include <platform/Types.h>
65 #include <utils/Time.h>
66 #include <utils/Singleton.h>
67 
68 namespace mira {
69 
71 // MAIN DEFINES
72 
73 #ifdef MIRA_PROFILER_ENABLED
74 # define MIRA_PROFILE_BEGIN(id) _MIRA_PROFILE_BEGIN(id)
75 # define MIRA_PROFILE_END(id) _MIRA_PROFILE_END (id)
76 # define MIRA_PROFILE_SCOPE(id) _MIRA_PROFILE_SCOPE(id)
77 #else
78 # define MIRA_PROFILE_BEGIN(id)
79 # define MIRA_PROFILE_END(id)
80 # define MIRA_PROFILE_SCOPE(id)
81 #endif
82 
83 
84 #ifndef MIRA_PROFILER_LEVEL
85 # define MIRA_PROFILER_LEVEL 3
86 #endif
87 
88 #if MIRA_PROFILER_LEVEL >= 1
89 # define MIRA_PROFILE_BEGIN1(id) MIRA_PROFILE_BEGIN(id)
90 # define MIRA_PROFILE_END1(id) MIRA_PROFILE_END(id)
91 # define MIRA_PROFILE_SCOPE1(id) MIRA_PROFILE_SCOPE(id)
92 #else
93 # define MIRA_PROFILE_BEGIN1(id)
94 # define MIRA_PROFILE_END1(id)
95 # define MIRA_PROFILE_SCOPE1(id)
96 #endif
97 
98 #if MIRA_PROFILER_LEVEL >= 2
99 # define MIRA_PROFILE_BEGIN2(id) MIRA_PROFILE_BEGIN(id)
100 # define MIRA_PROFILE_END2(id) MIRA_PROFILE_END(id)
101 # define MIRA_PROFILE_SCOPE2(id) MIRA_PROFILE_SCOPE(id)
102 #else
103 # define MIRA_PROFILE_BEGIN2(id)
104 # define MIRA_PROFILE_END2(id)
105 # define MIRA_PROFILE_SCOPE2(id)
106 #endif
107 
108 #if MIRA_PROFILER_LEVEL >= 3
109 # define MIRA_PROFILE_BEGIN3(id) MIRA_PROFILE_BEGIN(id)
110 # define MIRA_PROFILE_END3(id) MIRA_PROFILE_END(id)
111 # define MIRA_PROFILE_SCOPE3(id) MIRA_PROFILE_SCOPE(id)
112 #else
113 # define MIRA_PROFILE_BEGIN3(id)
114 # define MIRA_PROFILE_END3(id)
115 # define MIRA_PROFILE_SCOPE3(id)
116 #endif
117 
119 // internal macros
120 
121 #define __MIRA_PROFILE_BEGIN(id) \
122  static mira::Profiler::Node* _node_##id = \
123  mira::Profiler::instance().newProfileNode(#id,__FILE__, __LINE__); \
124  mira::Profiler::Node* _parent_##id = \
125  mira::Profiler::instance().beginHierarchy(_node_##id,__FILE__, __LINE__);\
126  uint64 _start_##id = mira::Profiler::getCycleCount();
127 
128 #define _MIRA_PROFILE_BEGIN(id) __MIRA_PROFILE_BEGIN(id)
129 
130 #define __MIRA_PROFILE_END(id) \
131  uint64 _duration_##id = mira::Profiler::getCycleCount() - _start_##id; \
132  mira::Profiler::instance().endHierarchy(_node_##id, _parent_##id, \
133  _duration_##id, __FILE__, __LINE__);
134 
135 #define _MIRA_PROFILE_END(id) __MIRA_PROFILE_END(id)
136 
137 #define __MIRA_PROFILE_SCOPE(id) \
138  static mira::Profiler::Node* _node_##id = \
139  mira::Profiler::instance().newProfileNode(#id,__FILE__, __LINE__); \
140  mira::Profiler::Scope _scope_##id(_node_##id,__FILE__, __LINE__);
141 
142 #define _MIRA_PROFILE_SCOPE(id) __MIRA_PROFILE_SCOPE(id)
143 
206 class MIRA_BASE_EXPORT Profiler : public EagerSingleton<Profiler>
207 {
208 public:
209 
211 
213  struct Node
214  {
215  struct ChildLink
216  {
217  ChildLink() : count(0), totalCycles(0), avgCycles(0.0), M2cycles(0.0), child(NULL) {}
218 
220  uint32 count;
221 
223  uint64 totalCycles;
224 
225  double avgCycles;
226  double M2cycles;
227 
229  Node* child;
230  };
231 
232  Node() : id(-1), filename(NULL), line(0), count(0), totalCycles(0), avgCycles(0.0), M2cycles(0.0) {}
233 
235  std::string name;
236 
238  int32 id;
239 
241  const char* filename;
242 
244  uint32 line;
245 
247  uint32 count;
248 
250  uint64 totalCycles;
251 
252  double avgCycles;
253  double M2cycles;
254 
256  std::vector<ChildLink> children;
257 
258  Spinlock spinlock;
259  };
260 
261  struct Report;
262  struct ReportNode;
263 
265 
266 public:
267 
268  Profiler();
269  ~Profiler();
270 
271 public:
272  static void writeReport(const std::string& directory,
273  const std::string& dotCommand="",
274  const std::string& imgFormat="png") {
275  Profiler::instance().writeReportInternal(directory, dotCommand, imgFormat);
276  }
277 
278 public:
279 
286  double getCPUSpeed();
287 
289  void setCPUSpeed(double speed) { mCPUSpeed.reset(speed); }
290 
291 public:
292 
293  // returns the current cycle count
294  static uint64 getCycleCount();
295 
296 public:
298 
299  // methods used internally be the profile macros
300 
305  Node* newProfileNode(const std::string& name,
306  const char* filename, uint32 line);
307 
311  Node* beginHierarchy(Node* node, const char* filename, uint32 line);
312 
317  void endHierarchy(Node* node, Node* prevNode, uint64 cycles,
318  const char* filename, uint32 line);
319 
321 
322 public:
323 
324  // helper for MIRA_PROFILE_SCOPE, which starts timing in constructor
325  // and stops it automatically in destructor when leaving the scope
326  struct Scope
327  {
328  Scope(Node* node, const char* filename, uint32 line) :
329  mNode(node), mFilename(filename), mLine(line),
330  mParent(instance().beginHierarchy(node,filename, line)),
331  mStart(getCycleCount()) {}
332 
334  {
335  uint64 duration = getCycleCount() - mStart;
336  instance().endHierarchy(mNode, mParent, duration, mFilename, mLine);
337  }
338 
339  private:
340  Node* mNode;
341  const char* mFilename;
342  int mLine;
343  Node* mParent;
344  uint64 mStart;
345  };
346 
347 private:
348 
349  typedef std::map<std::string, Node*> NodeMap;
350 
351  // the calibrated or specified cpu speed (in Hz)
352  boost::optional<double> mCPUSpeed;
353 
354  boost::mutex mMutex;
355 
356  // the collection of all profile nodes
357  NodeMap mNodes;
358 
359  // counter to generate a unique IDs
360  int32 mNextProfileID;
361 
362  struct ThreadInfo;
363  friend struct ThreadInfo;
364 
365  typedef boost::shared_ptr<ThreadInfo> ThreadInfoPtr;
366  boost::thread_specific_ptr<ThreadInfoPtr> mThreadInfo;
367  std::vector<ThreadInfoPtr> mThreads;
368 
369  static void threadInfoCleanupFn(ThreadInfo* t);
370 
371  ThreadInfo* getThreadInfo();
372 
373 private:
374 
375  void writeReportInternal(const std::string& directory,
376  std::string dotCommand,
377  const std::string& imgFormat);
378 
379  ReportNode* buildReportNode(Report* report, const Node* node);
380  void buildThreadReport(Report* report, const Node* node);
381 };
382 
384 
385 inline uint64 Profiler::getCycleCount()
386 {
387 #ifdef _MSC_VER
388 // Microsoft Visual C++
389 # ifdef _WIN64
390  return cycles = __rdtsc();
391 # else
392  uint64_t cycles;
393  __asm {
394  rdtsc
395  mov DWORD PTR[cycles] , eax
396  mov DWORD PTR[cycles+4], edx
397  }
398  return cycles
399 # endif
400 #else
401 // Linux, GCC
402 # if defined(MIRA_ARCH_X86)
403 # if defined(MIRA_ARCH64)
404  // x86 64-bit
405  unsigned hi, lo;
406  asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
407  return ( (uint64)lo) | (((uint64)hi)<<32 );
408 # else
409  // x86 32-bit
410  uint64 cycles;
411  asm volatile ("rdtsc" : "=A" (cycles));
412  return cycles;
413 # endif
414 # elif defined(MIRA_ARCH_ARM)
415 # if defined(MIRA_ARCH64)
416  // ARM 64-bit
417  uint64 cycles;
418  asm volatile ("mrs %0, cntvct_el0" : "=r" (cycles));
419  return cycles;
420 # else
421  // ARM 32-bit
422  return 0;
423 # endif
424 # else
425  return 0;
426 # endif
427 #endif
428 }
429 
431 
432 }
433 
434 #endif
Typedefs for OS independent basic data types.
void setCPUSpeed(double speed)
Overwrites the calibrated CPU speed with the specified value (in Hz!).
Definition: Profiler.h:289
Implementation of Spinlock.
~Scope()
Definition: Profiler.h:333
static Type & instance()
Returns a reference to the singleton instance.
Definition: Singleton.h:544
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
static void writeReport(const std::string &directory, const std::string &dotCommand="", const std::string &imgFormat="png")
Definition: Profiler.h:272
Time and Duration wrapper class.
Provided for convenience.
Definition: Singleton.h:572
Scope(Node *node, const char *filename, uint32 line)
Definition: Profiler.h:328
The main Profiler class.
Definition: Profiler.h:206
Includes, defines and functions for threads.
A singleton class that can be freely configured using policies that control the creation, instantiation, lifetime and thread-safety.
Definition: Profiler.h:326
static uint64 getCycleCount()
Definition: Profiler.h:385
#define MIRA_BASE_EXPORT
This is required because on windows there is a macro defined called ERROR.
Definition: Platform.h:153
A spinlock is similar to a mutex and allows thread synchronization of critical sections.
Definition: Spinlock.h:68