OpenLexocad  27.1
Profiny.h
Go to the documentation of this file.
1 /*
2  * Profiny - Lightweight Profiler Tool
3  * Copyright (C) 2013 Sercan Tutar
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; either version 2.1 of the License, or (at your option)
8  * any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software Foundation, Inc.,
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  *
20  * USAGE:
21  * First PROFINY_CALL_GRAPH_PROFILER or PROFINY_FLAT_PROFILER must be defined
22  * (giving as a compiler option is advised). If you;
23  *
24  * - define PROFINY_CALL_GRAPH_PROFILER, it will work as a call-graph profiler
25  * - define PROFINY_FLAT_PROFILER, it will work as a flat profiler
26  * - define neither, Profiny macros will be set to blank (i.e. profiling will be off)
27  * - define both, it will give an error
28  *
29  * Later, if you chose PROFINY_CALL_GRAPH_PROFILER, you may want to determine
30  * whether recursive calls will be omitted or not (omitted by default) by calling:
31  *
32  * Profiler::setOmitRecursiveCalls(bool)
33  *
34  * By default (if the profiling is not off), if your program exits normally, Profinity
35  * will print results in "profinity.out" file. Also, the user can force printing results
36  * at any time by calling:
37  *
38  * Profiler::printStats("filename")
39  *
40  * See ReadMe.txt for more info.
41  *
42  *
43  * Happy profiling!
44  *
45  */
46 
47 
48 #ifndef PROFINY_H_
49 #define PROFINY_H_
50 
51 
52 #include <boost/intrusive_ptr.hpp>
53 #include <boost/timer/timer.hpp>
54 #include <fstream>
55 #include <map>
56 #include <sstream>
57 #include <vector>
58 
59 
60 #if defined(PROFINY_CALL_GRAPH_PROFILER) && defined(PROFINY_FLAT_PROFILER)
61 
62 #error "PROFINY_CALL_GRAPH_PROFILER and PROFINY_FLAT_PROFILER should not be defined at the same time!"
63 
64 #elif defined(PROFINY_CALL_GRAPH_PROFILER) || defined(PROFINY_FLAT_PROFILER)
65 
66 #define PROFINY_SCOPE \
67  std::ostringstream _oss; \
68  _oss << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__; \
69  profiny::ScopedProfile _sco_pro(_oss.str());
70 
71 #define PROFINY_SCOPE_WITH_ID(ID) \
72  std::ostringstream _oss; \
73  _oss << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":" << (ID); \
74  profiny::ScopedProfile _sco_pro(_oss.str());
75 
76 #define PROFINY_NAMED_SCOPE(NAME) \
77  std::ostringstream _oss; \
78  _oss << (NAME); \
79  profiny::ScopedProfile _sco_pro(_oss.str());
80 
81 #define PROFINY_NAMED_SCOPE_WITH_ID(NAME, ID) \
82  std::ostringstream _oss; \
83  _oss << (NAME) << ":" << (ID); \
84  profiny::ScopedProfile _sco_pro(_oss.str());
85 
86 #else
87 
88 #define PROFINY_SCOPE
89 
90 #define PROFINY_SCOPE_WITH_ID(ID)
91 
92 #define PROFINY_NAMED_SCOPE(NAME)
93 
94 #define PROFINY_NAMED_SCOPE_WITH_ID(NAME, ID)
95 
96 #endif
97 
98 
99 #define NANOSEC_TO_SEC(X) ((X) / 1000000000.0)
100 
101 
102 namespace profiny
103 {
104 class BaseObject
105 {
106 public:
107  BaseObject();
108 
109  virtual ~BaseObject();
110 
111  void incrRef();
112 
113  void decrRef();
114 
115  int getRef() const;
116 
117 private:
118  int m_ref;
119 };
120 
121 /**********************************************************************/
122 
123 class Profile : public BaseObject
124 {
125  friend class ScopedProfile;
126  friend class Profiler;
127 
128 private:
129  Profile(const std::string& name);
130 
131  ~Profile();
132 
133  bool start();
134 
135  bool stop();
136 
137  unsigned int getCallCount() const;
138 
139  std::string getName() const;
140 
141  void getTimes(double& wall, double& user, double& system) const;
142 
143 #ifdef PROFINY_CALL_GRAPH_PROFILER
144  std::map<std::string, boost::intrusive_ptr<Profile> >& getSubProfiles();
145 
146  std::map<std::string, boost::intrusive_ptr<Profile> > m_subProfiles;
147 #else
148  bool m_timeStarted;
149 #endif
150 
151  std::string m_name;
152 
153  unsigned int m_callCount;
154 
155  double m_wallTime;
156  double m_userTime;
157  double m_systemTime;
158 
159  boost::timer::cpu_timer m_timer;
160 };
161 
162 /**********************************************************************/
163 
164 class ScopedProfile : public BaseObject
165 {
166 public:
167  ScopedProfile(const std::string& name);
168 
169  ~ScopedProfile();
170 
171 private:
172  boost::intrusive_ptr<Profile> m_profile;
173 };
174 
175 /**********************************************************************/
176 
177 class Profiler : public BaseObject
178 {
179  friend class Profile;
180  friend class ScopedProfile;
181 
182 public:
183  static void printStats(const std::string& filename);
184 
185 #ifdef PROFINY_CALL_GRAPH_PROFILER
186  static void setOmitRecursiveCalls(bool omit);
187 
188  static bool getOmitRecursiveCalls();
189 #endif
190 
191 private:
192  Profiler();
193 
194  ~Profiler();
195 
196  static boost::intrusive_ptr<Profiler> getInstance();
197 
198  boost::intrusive_ptr<Profile> getProfile(const std::string& name);
199 
200  static void printStats();
201 
202  static void printStats(std::ofstream& fs, std::map<std::string, boost::intrusive_ptr<Profile> >* p, int depth);
203 
204 #ifdef PROFINY_CALL_GRAPH_PROFILER
205  std::map<std::string, boost::intrusive_ptr<Profile> >& getCurrentProfilesRoot();
206 
207  void pushProfile(boost::intrusive_ptr<Profile> p);
208 
209  void popProfile();
210 
211  bool isInStack(const std::string& name);
212 #endif
213 
214  std::map<std::string, boost::intrusive_ptr<Profile> > m_profiles;
215 
216  static boost::intrusive_ptr<Profiler> m_instance;
217 
218 #ifdef PROFINY_CALL_GRAPH_PROFILER
219  std::vector<boost::intrusive_ptr<Profile> > m_profileStack;
220 
221  bool m_omitRecursiveCalls;
222 #endif
223 };
224 
225 /**********************************************************************/
226 
227 inline BaseObject::BaseObject() : m_ref(0)
228 {
229 }
230 
231 inline BaseObject::~BaseObject()
232 {
233 }
234 
235 inline void BaseObject::incrRef()
236 {
237  m_ref++;
238 }
239 
240 inline void BaseObject::decrRef()
241 {
242  m_ref--;
243 }
244 
245 inline int BaseObject::getRef() const
246 {
247  return m_ref;
248 }
249 
250 /**********************************************************************/
251 
252 inline Profile::Profile(const std::string& name)
253  :
254 #ifndef PROFINY_CALL_GRAPH_PROFILER
255  m_timeStarted(false)
256  ,
257 #endif
258  m_name(name)
259  , m_callCount(0)
260  , m_wallTime(0.0)
261  , m_userTime(0.0)
262  , m_systemTime(0.0)
263 {
264 }
265 
266 inline Profile::~Profile()
267 {
268 }
269 
270 inline bool Profile::start()
271 {
272 #ifdef PROFINY_CALL_GRAPH_PROFILER
273  Profiler::getInstance()->pushProfile(this);
274 #else
275  if (m_timeStarted)
276  {
277  return false;
278  }
279  m_timeStarted = true;
280 #endif
281  m_timer.start();
282  return true;
283 }
284 
285 inline bool Profile::stop()
286 {
287 #ifdef PROFINY_CALL_GRAPH_PROFILER
288  Profiler::getInstance()->popProfile();
289 #else
290  if (!m_timeStarted)
291  {
292  return false;
293  }
294  m_timeStarted = false;
295 #endif
296  m_timer.stop(); // TODO: check if we need this line
297  boost::timer::cpu_times t = m_timer.elapsed();
298  m_wallTime += NANOSEC_TO_SEC(t.wall);
299  m_userTime += NANOSEC_TO_SEC(t.user);
300  m_systemTime += NANOSEC_TO_SEC(t.system);
301  ++m_callCount;
302  return true;
303 }
304 
305 inline unsigned int Profile::getCallCount() const
306 {
307  return m_callCount;
308 }
309 
310 inline std::string Profile::getName() const
311 {
312  return m_name;
313 }
314 
315 inline void Profile::getTimes(double& wall, double& user, double& system) const
316 {
317  wall = m_wallTime;
318  user = m_userTime;
319  system = m_systemTime;
320 }
321 
322 #ifdef PROFINY_CALL_GRAPH_PROFILER
323 inline std::map<std::string, boost::intrusive_ptr<Profile> >& Profile::getSubProfiles()
324 {
325  return m_subProfiles;
326 }
327 #endif
328 
329 /**********************************************************************/
330 
331 inline ScopedProfile::ScopedProfile(const std::string& name)
332 {
333  std::string n(name);
334 
335 #ifdef PROFINY_CALL_GRAPH_PROFILER
336  if (Profiler::getInstance()->isInStack(n))
337  { // profile is already in stack (probably a recursive call)
338  if (Profiler::getInstance()->getOmitRecursiveCalls())
339  {
340  m_profile = NULL;
341  return;
342  }
343  else
344  {
345  n = "RECURSIVE@" + n;
346  }
347  }
348 #endif
349 
350  m_profile = Profiler::getInstance()->getProfile(n);
351  if (m_profile != NULL)
352  {
353  if (!m_profile->start())
354  { // cannot start profiler (probably a recursive call for flat profiler)
355  m_profile = NULL;
356  }
357  }
358  else
359  {
360  std::cerr << "Cannot start scoped profiler: " << n << std::endl;
361  }
362 }
363 
364 inline ScopedProfile::~ScopedProfile()
365 {
366  if (m_profile != NULL)
367  {
368  m_profile->stop();
369  }
370 }
371 
372 /**********************************************************************/
373 
374 boost::intrusive_ptr<Profiler> Profiler::m_instance = NULL;
375 
376 inline Profiler::Profiler()
377 #ifdef PROFINY_CALL_GRAPH_PROFILER
378  : m_omitRecursiveCalls(true)
379 #endif
380 {
381 }
382 
383 inline Profiler::~Profiler()
384 {
385 }
386 
387 inline boost::intrusive_ptr<Profiler> Profiler::getInstance()
388 {
389  if (m_instance == NULL)
390  {
391  m_instance = new Profiler;
392  atexit(printStats);
393  }
394  return m_instance;
395 }
396 
397 inline boost::intrusive_ptr<Profile> Profiler::getProfile(const std::string& name)
398 {
399 #ifdef PROFINY_CALL_GRAPH_PROFILER
400  std::map<std::string, boost::intrusive_ptr<Profile> >& profiles = getCurrentProfilesRoot();
401 #else
402  std::map<std::string, boost::intrusive_ptr<Profile> >& profiles = m_profiles;
403 #endif
404  std::map<std::string, boost::intrusive_ptr<Profile> >::iterator it = profiles.find(name);
405  if (it != profiles.end())
406  {
407  return it->second;
408  }
409  else
410  {
411  boost::intrusive_ptr<Profile> result = new Profile(name);
412  profiles[name] = result;
413  return result;
414  }
415 }
416 
417 #ifdef PROFINY_CALL_GRAPH_PROFILER
418 inline std::map<std::string, boost::intrusive_ptr<Profile> >& Profiler::getCurrentProfilesRoot()
419 {
420  return m_profileStack.empty() ? m_profiles : m_profileStack.back()->getSubProfiles();
421 }
422 
423 inline void Profiler::pushProfile(boost::intrusive_ptr<Profile> p)
424 {
425  m_profileStack.push_back(p);
426 }
427 
428 inline void Profiler::popProfile()
429 {
430  if (!m_profileStack.empty())
431  {
432  m_profileStack.pop_back();
433  }
434 }
435 
436 inline bool Profiler::isInStack(const std::string& name)
437 {
438  for (unsigned int i = 0; i < m_profileStack.size(); i++)
439  {
440  if (m_profileStack[i]->getName() == name)
441  {
442  return true;
443  }
444  }
445  return false;
446 }
447 #endif
448 
449 inline void Profiler::printStats(std::ofstream& fs, std::map<std::string, boost::intrusive_ptr<Profile> >* p, int depth)
450 {
451 #ifdef PROFINY_CALL_GRAPH_PROFILER
452  std::ostringstream oss;
453  for (int i = 0; i < depth; i++)
454  {
455  oss << "\t";
456  }
457 #endif
458 
459  std::map<std::string, boost::intrusive_ptr<Profile> >::iterator it = p->begin();
460  for (; it != p->end(); it++)
461  {
462  unsigned int cc = it->second->getCallCount();
463  double wall, user, system;
464  it->second->getTimes(wall, user, system);
465 #ifdef PROFINY_CALL_GRAPH_PROFILER
466  fs << oss.str() << it->second->getName() << " T:" << wall << " #:" << cc << " %:" << 100 * ((user + system) / wall) << std::endl;
467  printStats(fs, &(it->second->getSubProfiles()), depth + 1);
468 #else
469  fs << it->second->getName() << " T:" << wall << " #:" << cc << " %:" << 100 * ((user + system) / wall) << std::endl;
470 #endif
471  }
472 }
473 
474 inline void Profiler::printStats()
475 {
476  printStats("profiny.out");
477 }
478 
479 inline void Profiler::printStats(const std::string& filename)
480 {
481  std::ofstream fs;
482  fs.open(filename.c_str());
483  if (!fs.is_open())
484  {
485  std::cerr << "Cannot open profiler output file: " << filename << std::endl;
486  return;
487  }
488  Profiler::printStats(fs, &(getInstance()->m_profiles), 0);
489  fs.close();
490 }
491 
492 #ifdef PROFINY_CALL_GRAPH_PROFILER
493 inline void Profiler::setOmitRecursiveCalls(bool omit)
494 {
495  getInstance()->m_omitRecursiveCalls = omit;
496 }
497 
498 inline bool Profiler::getOmitRecursiveCalls()
499 {
500  return getInstance()->m_omitRecursiveCalls;
501 }
502 #endif
503 
504 } // namespace profiny
505 
506 /**********************************************************************/
507 
508 inline void intrusive_ptr_add_ref(profiny::BaseObject* p)
509 {
510  if (p != NULL)
511  { // pointer is not NULL
512  p->incrRef();
513  }
514 }
515 
516 inline void intrusive_ptr_release(profiny::BaseObject* p)
517 {
518  if (p != NULL)
519  { // pointer is not NULL
520  p->decrRef();
521  if (p->getRef() <= 0)
522  { // reference count is zero or less
523  delete p;
524  }
525  }
526 }
527 
528 #endif /* PROFINY_H_ */
Core::PropertyText name
Definition: CoreDocument.h:167
void intrusive_ptr_release(profiny::BaseObject *p)
Definition: Profiny.h:516
Core::PropertyText filename
Definition: CoreDocument.h:176
#define NANOSEC_TO_SEC(X)
Definition: Profiny.h:99
void intrusive_ptr_add_ref(profiny::BaseObject *p)
Definition: Profiny.h:508