RCFProto
 All Classes Functions Typedefs
Profile.hpp
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 2.0
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18 
19 #ifndef INCLUDE_UTIL_PROFILE_HPP
20 #define INCLUDE_UTIL_PROFILE_HPP
21 
22 #include <sys/types.h>
23 #include <sys/timeb.h>
24 
25 #include <iostream>
26 #include <map>
27 #include <memory>
28 #include <sstream>
29 #include <vector>
30 
31 #include "RCF/ThreadLibrary.hpp"
32 
33 namespace RCF {
34 
35  class ProfilingData;
36 
37  class ProfilingResults
38  {
39  private:
40  ProfilingResults()
41  {
42  }
43 
44  ~ProfilingResults();
45 
46  static ProfilingResults *&getSingletonPtrRef()
47  {
48  static ProfilingResults *pProfilingResults = NULL;
49  if (pProfilingResults == NULL)
50  {
51  pProfilingResults = new ProfilingResults();
52  }
53  return pProfilingResults;
54  }
55 
56  std::vector<ProfilingData *> pTlsData;
57 
58  public:
59  static ProfilingResults &getSingleton()
60  {
61  return *getSingletonPtrRef();
62  }
63  static void deleteSingleton()
64  {
65  delete getSingletonPtrRef();
66  getSingletonPtrRef() = NULL;
67  }
68  void dump()
69  {
70  RCF::Lock lock(mMutex);
71  for (unsigned int i=0; i<mResults.size(); i++)
72  {
73  std::ostringstream ostr;
74  ostr << "*************************\n";
75  ostr << "Profiling results for thread #" << i << ":\n";
76 
77  for (DataT::iterator iter_i = mResults[i]->begin(); iter_i != mResults[i]->end(); iter_i++) {
78  if (!(*iter_i).first.empty()) {
79  ostr << (*iter_i).first << ": " << (*iter_i).second.first / 1000.0 << " s.\n";
80  SubDataT &subData = (*iter_i).second.second;
81  for (SubDataT::iterator iter_j = subData.begin(); iter_j != subData.end(); iter_j++)
82  ostr << " " << (*iter_j).first << ": " << (*iter_j).second / 1000.0 << "s.\n";
83  }
84  }
85 
86  ostr << "*************************\n";
87  std::cout << ostr.str();
88  }
89  }
90 
91  private:
92  friend class ProfilingData;
93  typedef std::map<std::string, unsigned int> SubDataT;
94  typedef std::map<std::string, std::pair<unsigned int, SubDataT > > DataT;
95 
96  RCF::Mutex mMutex;
97  std::vector< DataT * > mResults;
98 
99  void add( DataT *data )
100  {
101  RCF::Lock scoped_lock( mMutex );
102  mResults.push_back( data );
103  }
104 
105  };
106 
107  class ProfilingData
108  {
109  private:
110  ProfilingData() : stack_(100), data_(new DataT()) { ProfilingResults::getSingleton().add( data_ ); }
111  public:
112  ~ProfilingData()
113  {
114  delete data_;
115  data_ = NULL;
116  }
117 
118  static ProfilingData &getThreadSpecificInstance()
119  {
120  static RCF::ThreadSpecificPtr<ProfilingData>::Val profilingData;
121 
122  if (NULL == profilingData.get())
123  {
124  profilingData.reset(new ProfilingData());
125  ProfilingResults::getSingleton().pTlsData.push_back(profilingData);
126  profilingData->push("");
127  }
128  return *profilingData;
129  }
130 
131  void push(std::string sz)
132  {
133  stack_.push_back(sz);
134  }
135 
136  void pop()
137  {
138  stack_.pop_back();
139  }
140 
141  void add(unsigned int timespan)
142  {
143  std::string cur = stack_[stack_.size()-1];
144  std::string prev = stack_[stack_.size()-2];
145  (*data_)[cur].first += timespan;
146  (*data_)[prev].second[cur] += timespan;
147  }
148 
149  private:
150  typedef ProfilingResults::DataT DataT;
151  std::vector<std::string> stack_;
152  DataT *data_;
153  };
154 
155  inline unsigned int getTickCount()
156  {
157  return RCF::getCurrentTimeMs();
158  }
159 
160  class Profile
161  {
162  public:
163  Profile(const std::string &name) : name(name), t0(getTickCount()), t1(0)
164  {
165  ProfilingData::getThreadSpecificInstance().push(name);
166  }
167 
168  void stop()
169  {
170  t1 = getTickCount();
171  ProfilingData::getThreadSpecificInstance().add(t1 - t0);
172  ProfilingData::getThreadSpecificInstance().pop();
173  }
174 
175 
176  ~Profile()
177  {
178  if (!t1)
179  {
180  stop();
181  }
182  }
183 
184  int getDurationMs()
185  {
186  RCF_ASSERT(t1);
187  return t1 - t0;
188  }
189 
190  private:
191  std::string name;
192  unsigned int t0;
193  unsigned int t1;
194  };
195 
196  class ImmediateProfile
197  {
198  public:
199  ImmediateProfile(const std::string &name) :
200  mName(name),
201  t0Ms(getTickCount()),
202  t1Ms()
203  {}
204 
205  ~ImmediateProfile()
206  {
207  t1Ms = getTickCount();
208  std::ostringstream ostr;
209  ostr << "Profile result: " << mName << ": " << t1Ms-t0Ms << "ms" << std::endl;
210  std::cout << ostr.str();
211  }
212 
213  private:
214  std::string mName;
215  unsigned int t0Ms;
216  unsigned int t1Ms;
217  };
218 
219  ProfilingResults::~ProfilingResults()
220  {
221  for (std::size_t i=0; i<pTlsData.size(); ++i)
222  {
223  delete pTlsData[i];
224  }
225  pTlsData.clear();
226  }
227 
228 
229 } // namespace RCF
230 
231 #endif