GSLAM  3.0.0
Timer.h
1 // GSLAM - A general SLAM framework and benchmark
2 // Copyright 2018 PILAB Inc. All rights reserved.
3 // https://github.com/zdzhaoyong/GSLAM
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors may be
14 // used to endorse or promote products derived from this software without
15 // specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 // Author: zd5945@126.com (Yong Zhao)
30 //
31 // Timer is used to provide time usage distribution statistics
32 
33 #ifndef GSLAM_TIMER_H
34 #define GSLAM_TIMER_H
35 #include <iostream>
36 #include <sstream>
37 #include <iomanip>
38 #include <stdint.h>
39 #include <vector>
40 #include <stack>
41 #include <map>
42 #include <string>
43 #include <chrono>
44 #include <thread>
45 #include <mutex>
46 #include <memory>
47 
48 namespace GSLAM {
49 
50 class TicToc
51 {
52 public:
53  TicToc(){Tic();}
54 
55  void Tic(){
56  _tmBegin=std::chrono::high_resolution_clock::now();
57  }
58  double Toc(){
59  return std::chrono::duration<double>(std::chrono::high_resolution_clock::now()-_tmBegin).count();
60  }
61 
62  double Tac(){return Toc();}
63 
64  static double timestamp(){
65  return std::chrono::duration<double>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
66  }
67 
68 protected:
69 std::chrono::high_resolution_clock::time_point _tmBegin;
70 };
71 
72 class Rate
73 {
74 public:
75  Rate(double frequency=1.0)
76  {
77  _cycle=1./frequency;
78  _tmBegin=std::chrono::system_clock::now();
79  }
80 
81  static void sleep(double seconds)
82  {
83  if(seconds>0)
84  std::this_thread::sleep_for(std::chrono::duration<double>(seconds));
85  }
86 
87  void sleep(){
88  std::chrono::system_clock::time_point now=std::chrono::system_clock::now();
89  sleep(_cycle-std::chrono::duration<double>(now-_tmBegin).count());
90  _tmBegin=now;
91  }
92 
93  double _cycle;
94  std::chrono::system_clock::time_point _tmBegin;
95 };
96 
97 class Timer : public TicToc
98 {
99 private:
100  bool m_enabled;
101 
102  //! Data of all the calls:
103  struct TCallData
104  {
105  TCallData();
106 
107  size_t n_calls;
108  double min_t,max_t,mean_t;
109  std::stack<double,std::vector<double> > open_calls;
110  bool has_time_units;
111  };
112 
113  std::map<std::string,TCallData> m_data;
114  mutable std::mutex mMutex;
115 
116  void do_enter( const char *func_name );
117  double do_leave( const char *func_name );
118 
119 public:
120  Timer(bool enabled=true):m_enabled(enabled){Tic();}
121  ~Timer();
122 
123  static Timer& instance(){
124  static std::shared_ptr<Timer> globalTimer(new Timer());
125  return *globalTimer;
126  }
127 
128  void enable(bool enabled = true) { m_enabled = enabled; }
129  void disable() { m_enabled = false; }
130 
131  /** Start of a named section \sa enter */
132  inline void enter( const char *func_name ) {
133  if (m_enabled)
134  do_enter(func_name);
135  }
136 
137  /** End of a named section \return The ellapsed time, in seconds or 0 if disabled. \sa enter */
138  inline double leave( const char *func_name ) {
139  return m_enabled ? do_leave(func_name) : 0;
140  }
141 
142  /** Return the mean execution time of the given "section", or 0 if it hasn't ever been called "enter" with that section name */
143  double getMeanTime(const std::string &name) const;
144  std::string getStatsAsText(const size_t column_width=80) const; //!< Dump all stats to a multi-line text string. \sa dumpAllStats, saveToCVSFile
145  void dumpAllStats(const size_t column_width=80) const; //!< Dump all stats through the CDebugOutputCapable interface. \sa getStatsAsText, saveToCVSFile
146 
147 };
148 
150 {
151 public:
152  ScopedTimer(const char* func_name)
153  :_func_name(func_name){Timer::instance().enter(func_name);}
154  ~ScopedTimer(){Timer::instance().leave(_func_name);}
155  const char* _func_name;
156 };
157 ////////////////////////////////////////////////////////////////////////////////
158 ////////////////////////////////////////////////////////////////////////////////
159 
160 inline Timer::TCallData::TCallData() :
161  n_calls (0),
162  min_t (0),
163  max_t (0),
164  mean_t (0),
165  has_time_units(true)
166 {
167 
168 }
169 
170 inline Timer::~Timer()
171 {
172  dumpAllStats();
173  m_data.clear();
174 }
175 
176 
177 inline void Timer::do_enter(const char *func_name)
178 {
179  using namespace std;
180  const string s = func_name;
181  TCallData *d=NULL;
182  {
183  std::unique_lock<std::mutex> lock(mMutex);
184  map<string,TCallData>::iterator it=m_data.find(s);
185  if(it==m_data.end())
186  {
187  it=m_data.insert(make_pair(s,TCallData())).first;
188  }
189  d =& it->second;
190  }
191 
192  d->n_calls++;
193  d->open_calls.push(0); // Dummy value, it'll be written below
194  d->open_calls.top() = Tac(); // to avoid possible delays.
195 }
196 
197 inline double Timer::do_leave(const char *func_name)
198 {
199  using namespace std;
200  const double tim = Tac();
201 
202  const string s = func_name;
203  TCallData *d=NULL;
204  {
205  std::unique_lock<std::mutex> lock(mMutex);
206  d = &m_data[s];
207  }
208  if (!d->open_calls.empty())
209  {
210  const double At = tim - d->open_calls.top();
211  d->open_calls.pop();
212 
213  d->mean_t+=At;
214  if (d->n_calls==1)
215  {
216  d->min_t= At;
217  d->max_t= At;
218  }
219  else
220  {
221  if (d->min_t>At) d->min_t = At;
222  if (d->max_t<At) d->max_t = At;
223  }
224  return At;
225  }
226  else return 0; // This shouldn't happen!
227 }
228 
229 inline double Timer::getMeanTime(const std::string &name) const
230 {
231  using namespace std;
232  std::unique_lock<std::mutex> lock(mMutex);
233  map<string,TCallData>::const_iterator it = m_data.find(name);
234  if (it==m_data.end())
235  return 0;
236  else return it->second.n_calls ? it->second.mean_t/it->second.n_calls : 0;
237 }
238 
239 inline std::string unitsFormat(const double val,int nDecimalDigits, bool middle_space)
240 {
241  using namespace std;
242  char prefix;
243  double mult;
244 
245  if (val>=1e12)
246  {mult=1e-12; prefix='T';}
247  else if (val>=1e9)
248  {mult=1e-9; prefix='G';}
249  else if (val>=1e6)
250  {mult=1e-6; prefix='M';}
251  else if (val>=1e3)
252  {mult=1e-3; prefix='K';}
253  else if (val>=1)
254  {mult=1; prefix=' ';}
255  else if (val>=1e-3)
256  {mult=1e+3; prefix='m';}
257  else if (val>=1e-6)
258  {mult=1e+6; prefix='u';}
259  else if (val>=1e-9)
260  {mult=1e+9; prefix='n';}
261  else if (val>=1e-12)
262  {mult=1e+12; prefix='p';}
263  else
264  {mult=0; prefix='p';}
265 
266  ostringstream ost;
267  ost<<setw(5) <<setiosflags(ios::fixed) <<setiosflags(ios::right)
268  << setprecision(1)<<(val*mult);
269 
270  return ost.str()+char(prefix);
271 }
272 
273 inline std::string rightPad(const std::string &str, const size_t total_len, bool truncate_if_larger)
274 {
275  std::string r = str;
276  if (r.size()<total_len || truncate_if_larger)
277  r.resize(total_len,' ');
278  return r;
279 }
280 
281 inline std::string aux_format_string_multilines(const std::string &s, const size_t len)
282 {
283  std::string ret;
284 
285  for (size_t p=0;p<s.size();p+=len)
286  {
287  ret+=rightPad(s.c_str()+p,len,true);
288  if (p+len<s.size())
289  ret+="\n";
290  }
291  return ret;
292 }
293 
294 inline std::string Timer::getStatsAsText(const size_t column_width) const
295 {
296  std::unique_lock<std::mutex> lock(mMutex);
297  using namespace std;
298  ostringstream ost;
299  ost<<"------------------------------------ Timer report ------------------------------------\n";
300  ost<<" FUNCTION #CALLS MIN.T MEAN.T MAX.T TOTAL \n";
301  ost<<"---------------------------------------------------------------------------------------\n";
302  for (map<string,TCallData>::const_iterator i=m_data.begin();i!=m_data.end();++i)
303  {
304  const string sMinT = unitsFormat(i->second.min_t,1,false);
305  const string sMaxT = unitsFormat(i->second.max_t,1,false);
306  const string sTotalT = unitsFormat(i->second.mean_t,1,false);
307  const string sMeanT = unitsFormat(i->second.n_calls ? i->second.mean_t/i->second.n_calls : 0,1,false);
308 
309  ost << aux_format_string_multilines(i->first,39)
310  << " " << setw(6) << setiosflags(ios::right) << i->second.n_calls <<" "
311  << sMinT << "s " << sMeanT << "s " << sMaxT << "s "
312  << sTotalT << "s\n";
313  }
314 
315  ost<<"--------------------------------- End of Timer report ---------------------------------\n";
316 
317  return ost.str();
318 }
319 
320 inline void Timer::dumpAllStats(const size_t column_width) const
321 {
322  using namespace std;
323  if(!m_data.size()||!m_enabled) return;
324  string s = getStatsAsText(column_width);
325  cout<<endl<<s<<endl;
326 }
327 
328 
329 }
330 #endif // TIME_H
void enter(const char *func_name)
Start of a named section.
Definition: Timer.h:132
double leave(const char *func_name)
End of a named section.
Definition: Timer.h:138
std::string getStatsAsText(const size_t column_width=80) const
Dump all stats to a multi-line text string.
Definition: Timer.h:294
Definition: Timer.h:72
Definition: Timer.h:97
Definition: Camera.h:45
Definition: Timer.h:50
double getMeanTime(const std::string &name) const
Return the mean execution time of the given "section", or 0 if it hasn&#39;t ever been called "enter" wit...
Definition: Timer.h:229
void dumpAllStats(const size_t column_width=80) const
Dump all stats through the CDebugOutputCapable interface.
Definition: Timer.h:320
Definition: Timer.h:149