GCS  0.2.3
gu_profile.hpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2010 Codership Oy <info@codership.com>
3 //
4 
44 #ifndef GU_PROFILE_HPP
45 #define GU_PROFILE_HPP
46 
47 #include "gu_time.h"
48 #include "gu_datetime.hpp"
49 #include "gu_lock.hpp"
50 
51 #if defined(HAVE_BOOST_UNORDERED_MAP_HPP)
52 #include <boost/unordered_map.hpp>
53 #elif defined(HAVE_UNORDERED_MAP)
54 #include <unordered_map>
55 #elif defined(HAVE_TR1_UNORDERED_MAP)
56 #include <tr1/unordered_map>
57 #else
58 #include <map>
59 #endif // HAVE_BOOST_UNORDERED_MAP_HPP
60 
61 #include <ostream>
62 
63 namespace gu
64 {
65  namespace prof
66  {
67  class Key;
68  class KeyHash;
69  class Point;
70  class Profile;
71  std::ostream& operator<<(std::ostream&, const Key&);
72  std::ostream& operator<<(std::ostream&, const Profile&);
73  }
74 }
75 
81 {
82 public:
83  Key(const char* const file,
84  const char* const func,
85  const int line) :
86  file_(file),
87  func_(func),
88  line_(line)
89  { }
90 
91  bool operator==(const Key& cmp) const
92  {
93  return (line_ == cmp.line_ &&
94  func_ == cmp.func_ &&
95  file_ == cmp.file_);
96  }
97 
98  bool operator<(const Key& cmp) const
99  {
100  return (line_ < cmp.line_ ||
101  (line_ == cmp.line_ && (func_ < cmp.func_ ||
102  (func_ == cmp.func_ && file_ < cmp.file_))));
103  }
104  std::string to_string() const
105  {
106  std::ostringstream os;
107  os << *this;
108  return os.str();
109  }
110 private:
111  friend class KeyHash;
112  friend class Point;
113  friend class Profile;
114  friend std::ostream& operator<<(std::ostream& os, const Key&);
115  const char* const file_;
116  const char* const func_;
117  const int line_;
118 };
119 
120 #ifdef HAVE_BOOST_UNORDERED_MAP_HPP
121 class gu::prof::KeyHash
122 {
123 public:
124  size_t operator()(const Key& key) const
125  {
126  return boost::hash_value(key.file_)
127  ^ boost::hash_value(key.func_)
128  ^ boost::hash_value(key.line_);
129 
130  }
131 };
132 #endif // HAVE_BOOST_UNORDERED_MAP_HPP
133 
134 inline std::ostream& gu::prof::operator<<(std::ostream& os,
135  const gu::prof::Key& key)
136 {
137  return os << key.file_ << ":" << key.func_ << ":" << key.line_;
138 }
139 
140 
142 {
143 public:
144  Point(const Profile& prof,
145  const char* file,
146  const char* func,
147  const int line);
148  ~Point();
149 private:
150  friend class Profile;
151  const Profile& prof_;
152  const Key key_;
153  mutable long long int enter_time_calendar_;
154  mutable long long int enter_time_thread_cputime_;
155 };
156 
157 
162 {
163  struct PointStats
164  {
165  PointStats(long long int count = 0,
166  long long int time_calendar = 0,
167  long long int time_thread_cputime = 0) :
168  count_ (count ),
169  time_calendar_ (time_calendar ),
170  time_thread_cputime_(time_thread_cputime)
171  { }
172 
173  PointStats operator+(const PointStats& add) const
174  {
175  return PointStats(count_ + add.count_,
176  time_calendar_ + add.time_calendar_,
177  time_thread_cputime_+ add.time_thread_cputime_);
178  }
179 
180  long long int count_;
181  long long int time_calendar_;
182  long long int time_thread_cputime_;
183  };
184 #if defined(HAVE_BOOST_UNORDERED_MAP_HPP)
185  typedef boost::unordered_map<Key, PointStats, KeyHash> Map;
186 #elif defined(HAVE_UNORDERED_MAP)
187  typedef std::unordered_map<Key, PointStats, KeyHash> Map;
188 #elif defined(HAVE_TR1_UNORDERED_MAP)
189  typedef std::tr1::unordered_map<Key, PointStats, KeyHash> Map;
190 #else
191  typedef std::map<Key, PointStats> Map;
192 #endif
193 public:
199  Profile(const std::string& name = "profile") :
200  name_(name),
201  start_time_calendar_(gu_time_calendar()),
202  start_time_thread_cputime_(gu_time_thread_cputime()),
203  mutex_(),
204  points_()
205  { }
206 
207  void enter(const Point& point) const
208  {
209  point.enter_time_calendar_ = gu_time_calendar();
210  point.enter_time_thread_cputime_ = gu_time_thread_cputime();
211  gu::Lock lock(mutex_);
212  points_[point.key_].count_++;
213  }
214 
215  void leave(const Point& point) const
216  {
217  long long int t_cal(gu_time_calendar());
218  long long int t_thdcpu(gu_time_thread_cputime());
219 
220  gu::Lock lock(mutex_);
221  PointStats& pointst(points_[point.key_]);
222  pointst.time_calendar_ +=
223  (t_cal - point.enter_time_calendar_);
224  pointst.time_thread_cputime_ +=
225  (t_thdcpu - point.enter_time_thread_cputime_);
226  }
227 
228  void clear() const
229  {
230  gu::Lock lock(mutex_);
231  points_.clear();
232  }
233 
234  friend std::ostream& operator<<(std::ostream&, const Profile&);
235 
236  std::string const name_;
237  long long int const start_time_calendar_;
238  long long int const start_time_thread_cputime_;
239  gu::Mutex mutex_;
240  mutable Map points_;
241 };
242 
243 inline gu::prof::Point::Point(const Profile& prof,
244  const char* file,
245  const char* func,
246  const int line) :
247  prof_(prof),
248  key_(file, func, line),
249  enter_time_calendar_(),
250  enter_time_thread_cputime_()
251 {
252  prof_.enter(*this);
253 }
254 
255 inline gu::prof::Point::~Point()
256 {
257  prof_.leave(*this);
258 }
259 
260 
261 //
262 // Ostream operator for Profile class.
263 //
264 inline std::ostream& gu::prof::operator<<(std::ostream& os, const Profile& prof)
265 {
266 
267  Profile::PointStats cumul;
268 
269  char prev_fill(os.fill());
270  os.fill(' ');
271  os << "\nprofile name: " << prof.name_;
272 
273  os << std::left << std::fixed << std::setprecision(3);
274  os << "\n\n";
275  os << std::setw(40) << "point";
276  os << std::setw(10) << "count";
277  os << std::setw(10) << "calendar";
278  os << std::setw(10) << "cpu";
279  os << "\n"
280  << std::setfill('-') << std::setw(70) << ""
281  << std::setfill(' ') << "\n";
282  for (Profile::Map::const_iterator i = prof.points_.begin();
283  i != prof.points_.end(); ++i)
284  {
285  os << std::setw(40) << std::left << i->first.to_string();
286  os << std::right;
287  os << std::setw(10) << i->second.count_;
288  os << std::setw(10) << double(i->second.time_calendar_)*1.e-9;
289  os << std::setw(10) << double(i->second.time_thread_cputime_)*1.e-9;
290  os << std::left;
291  os << "\n";
292  cumul = cumul + i->second;
293  }
294 
295  os << "\ntot count : " << cumul.count_;
296  os << "\ntot calendar time : " << double(cumul.time_calendar_)*1.e-9;
297  os << "\ntot thread cputime: " << double(cumul.time_thread_cputime_)*1.e-9;
298  os << "\ntot ct since ctor : "
299  << double(gu::datetime::Date::now().get_utc() - prof.start_time_calendar_)*1.e-9;
300 
301  os.fill(prev_fill);
302  return os;
303 }
304 
305 
306 //
307 // Convenience macros for defining profile entry and leave points.
308 // If GU_PROFILE is undefined, these macros expand to no-op.
309 //
310 #ifdef GU_PROFILE
311 #define profile_enter(__p) \
312  do { \
313  const gu::prof::Point __point((__p), __FILE__, \
314  __FUNCTION__, __LINE__); \
315 
316 #define profile_leave(__p) \
317  } while (0)
318 #else
319 #define profile_enter(__p)
320 #define profile_leave(__p)
321 #endif // GU_PROFILE
322 
323 #endif // GU_PROFILE_HPP
Definition: gu_lock.hpp:20
Definition: gu_profile.hpp:161
Definition: gu_mutex.hpp:19
Profile(const std::string &name="profile")
Definition: gu_profile.hpp:199
Definition: gu_profile.hpp:80
Definition: gu_profile.hpp:141
static Date now()
Get system time.
Definition: gu_datetime.hpp:124