00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <iostream>
00023 #include "Profiler.h"
00024
00025 #include <vector>
00026 #include <algorithm>
00027 #include <set>
00028 #include <map>
00029
00030 using std::cerr;
00031 using std::endl;
00032
00033 Profiles* Profiles::m_instance = 0;
00034
00035 Profiles* Profiles::getInstance()
00036 {
00037 if (!m_instance) m_instance = new Profiles();
00038
00039 return m_instance;
00040 }
00041
00042 Profiles::Profiles()
00043 {
00044 }
00045
00046 Profiles::~Profiles()
00047 {
00048 dump();
00049 }
00050
00051 void Profiles::accumulate(
00052 #ifndef NO_TIMING
00053 const char* id, clock_t time, RealTime rt
00054 #else
00055 const char*, clock_t, RealTime
00056 #endif
00057 )
00058 {
00059 #ifndef NO_TIMING
00060 ProfilePair &pair(m_profiles[id]);
00061 ++pair.first;
00062 pair.second.first += time;
00063 pair.second.second = pair.second.second + rt;
00064
00065 TimePair &lastPair(m_lastCalls[id]);
00066 lastPair.first = time;
00067 lastPair.second = rt;
00068
00069 TimePair &worstPair(m_worstCalls[id]);
00070 if (time > worstPair.first) {
00071 worstPair.first = time;
00072 }
00073 if (rt > worstPair.second) {
00074 worstPair.second = rt;
00075 }
00076 #endif
00077 }
00078
00079 void Profiles::dump() const
00080 {
00081 #ifndef NO_TIMING
00082
00083 fprintf(stderr, "Profiling points:\n");
00084
00085 fprintf(stderr, "\nBy name:\n");
00086
00087 typedef std::set<const char *, std::less<std::string> > StringSet;
00088
00089 StringSet profileNames;
00090 for (ProfileMap::const_iterator i = m_profiles.begin();
00091 i != m_profiles.end(); ++i) {
00092 profileNames.insert(i->first);
00093 }
00094
00095 for (StringSet::const_iterator i = profileNames.begin();
00096 i != profileNames.end(); ++i) {
00097
00098 ProfileMap::const_iterator j = m_profiles.find(*i);
00099
00100 if (j == m_profiles.end()) continue;
00101
00102 const ProfilePair &pp(j->second);
00103
00104 fprintf(stderr, "%s(%d):\n", *i, pp.first);
00105
00106 fprintf(stderr, "\tCPU: \t%.9g ms/call \t[%d ms total]\n",
00107 (((double)pp.second.first * 1000.0 /
00108 (double)pp.first) / CLOCKS_PER_SEC),
00109 int((pp.second.first * 1000.0) / CLOCKS_PER_SEC));
00110
00111 fprintf(stderr, "\tReal: \t%s ms \t[%s ms total]\n",
00112 ((pp.second.second / pp.first) * 1000).toString().c_str(),
00113 (pp.second.second * 1000).toString().c_str());
00114
00115 WorstCallMap::const_iterator k = m_worstCalls.find(*i);
00116 if (k == m_worstCalls.end()) continue;
00117
00118 const TimePair &wc(k->second);
00119
00120 fprintf(stderr, "\tWorst:\t%s ms/call \t[%d ms CPU]\n",
00121 (wc.second * 1000).toString().c_str(),
00122 int((wc.first * 1000.0) / CLOCKS_PER_SEC));
00123 }
00124
00125 typedef std::multimap<RealTime, const char *> TimeRMap;
00126 typedef std::multimap<int, const char *> IntRMap;
00127
00128 TimeRMap totmap, avgmap, worstmap;
00129 IntRMap ncallmap;
00130
00131 for (ProfileMap::const_iterator i = m_profiles.begin();
00132 i != m_profiles.end(); ++i) {
00133 totmap.insert(TimeRMap::value_type(i->second.second.second, i->first));
00134 avgmap.insert(TimeRMap::value_type(i->second.second.second /
00135 i->second.first, i->first));
00136 ncallmap.insert(IntRMap::value_type(i->second.first, i->first));
00137 }
00138
00139 for (WorstCallMap::const_iterator i = m_worstCalls.begin();
00140 i != m_worstCalls.end(); ++i) {
00141 worstmap.insert(TimeRMap::value_type(i->second.second,
00142 i->first));
00143 }
00144
00145
00146 fprintf(stderr, "\nBy total:\n");
00147 for (TimeRMap::const_iterator i = totmap.end(); i != totmap.begin(); ) {
00148 --i;
00149 fprintf(stderr, "%-40s %s ms\n", i->second,
00150 (i->first * 1000).toString().c_str());
00151 }
00152
00153 fprintf(stderr, "\nBy average:\n");
00154 for (TimeRMap::const_iterator i = avgmap.end(); i != avgmap.begin(); ) {
00155 --i;
00156 fprintf(stderr, "%-40s %s ms\n", i->second,
00157 (i->first * 1000).toString().c_str());
00158 }
00159
00160 fprintf(stderr, "\nBy worst case:\n");
00161 for (TimeRMap::const_iterator i = worstmap.end(); i != worstmap.begin(); ) {
00162 --i;
00163 fprintf(stderr, "%-40s %s ms\n", i->second,
00164 (i->first * 1000).toString().c_str(), i->second);
00165 }
00166
00167 fprintf(stderr, "\nBy number of calls:\n");
00168 for (IntRMap::const_iterator i = ncallmap.end(); i != ncallmap.begin(); ) {
00169 --i;
00170 fprintf(stderr, "%-40s %d\n", i->second, i->first);
00171 }
00172
00173 #endif
00174 }
00175
00176 #ifndef NO_TIMING
00177
00178 Profiler::Profiler(const char* c, bool showOnDestruct)
00179 : m_c(c),
00180 m_showOnDestruct(showOnDestruct)
00181 {
00182 m_startCPU = clock();
00183
00184 struct timeval tv;
00185 (void)gettimeofday(&tv, 0);
00186 m_startTime = RealTime::fromTimeval(tv);
00187 }
00188
00189 void
00190 Profiler::update() const
00191 {
00192 clock_t elapsedCPU = clock() - m_startCPU;
00193
00194 struct timeval tv;
00195 (void)gettimeofday(&tv, 0);
00196 RealTime elapsedTime = RealTime::fromTimeval(tv) - m_startTime;
00197
00198 cerr << "Profiler : id = " << m_c
00199 << " - elapsed so far = " << ((elapsedCPU * 1000) / CLOCKS_PER_SEC)
00200 << "ms CPU, " << elapsedTime << " real" << endl;
00201 }
00202
00203 Profiler::~Profiler()
00204 {
00205 clock_t elapsedCPU = clock() - m_startCPU;
00206
00207 struct timeval tv;
00208 (void)gettimeofday(&tv, 0);
00209 RealTime elapsedTime = RealTime::fromTimeval(tv) - m_startTime;
00210
00211 Profiles::getInstance()->accumulate(m_c, elapsedCPU, elapsedTime);
00212
00213 if (m_showOnDestruct)
00214 cerr << "Profiler : id = " << m_c
00215 << " - elapsed = " << ((elapsedCPU * 1000) / CLOCKS_PER_SEC)
00216 << "ms CPU, " << elapsedTime << " real" << endl;
00217 }
00218
00219 #endif
00220