Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Profiler.cc

Go to the documentation of this file.
00001 #include "Profiler.h"
00002 #include "debuget.h"
00003 
00004 const float Profiler::HistCurve = 4.05;
00005 
00006 float Profiler::buckets[Profiler::HistSize];
00007 
00008 unsigned int Profiler::infosOffset=((size_t)(&static_cast<ProfilerOfSize<1>*>(NULL)[1].infos))-((size_t)(&static_cast<ProfilerOfSize<1>*>(NULL)[1].prof));
00009 
00010 ProfilerOfSize<20> * mainProfiler=NULL;
00011 ProfilerOfSize<06> * motionProfiler=NULL;
00012 ProfilerOfSize<06> * soundProfiler=NULL;
00013 
00014 /*! Tells the profiler that this is now the active timer, so new timers will fit "under" this.\n
00015  *  Timer isn't actually started here, lets Profiler::setCurrent do that.
00016  *  @param prof profiler to report results to.  If is NULL, does nothing.
00017  *  @param id id number for this function.  See Profiler::getNewID() for what you should pass this */
00018 Profiler::Timer::Timer(unsigned int id, Profiler* prof) : _prof(prof), _id(id), _parent(-1U), _t(0L) {
00019   if(_prof!=NULL)
00020     _prof->setCurrent(*this);
00021 }
00022 
00023 Profiler::Timer::~Timer() {
00024   if(_prof!=NULL)
00025     _prof->finished(*this);
00026 }
00027 
00028 void Profiler::Timer::setID(unsigned int id, Profiler* prof) {
00029   _id=id;
00030   _prof=prof;
00031   if(_prof!=NULL)
00032     _prof->setCurrent(*this);
00033 } 
00034 
00035 Profiler::SectionInfo::SectionInfo()
00036   : totalTime(0L),lastTime(0L),totalInterval(0L),childTime(0L),execExpAvg(0),interExpAvg(0),calls(0)
00037 {
00038   name[0]='\0';
00039   for(unsigned int j=0; j<HistSize; j++)
00040     execHist[j]=interHist[j]=0;
00041 }
00042 
00043 void Profiler::SectionInfo::reset() {
00044   totalTime.Set(0L);
00045   lastTime.Set();
00046   totalInterval.Set(0L);
00047   childTime.Set(0L);
00048   execExpAvg=0;
00049   interExpAvg=0;
00050   for(unsigned int j=0; j<HistSize; j++)
00051     execHist[j]=interHist[j]=0;
00052   calls=0;
00053 }
00054 
00055 void Profiler::initBuckets() {
00056   float g=HistTime/pow(HistSize,HistCurve)/1000;
00057   for(unsigned int i=1; i<=HistSize; i++)
00058     buckets[i-1]=g*pow(i,HistCurve);
00059 }
00060 
00061 unsigned int Profiler::getNewID(const char* name) {
00062   ASSERTRETVAL(sectionsUsed<maxSections,"Too many sections registered (increase ProfilerOfSize<MaxSections>)",-1U);
00063   SectionInfo * infos=getInfos();
00064 #ifdef DEBUG
00065   for(unsigned int i=0; i<sectionsUsed; i++)
00066     ASSERTRETVAL(strncmp(infos[i].name,name,MaxSectionNameLen-1)!=0,"Already using name " << name,-1U);
00067 #endif
00068   unsigned int id=sectionsUsed++;
00069   strncpy(infos[id].name,name,MaxSectionNameLen-1);
00070   infos[id].name[MaxSectionNameLen-1]='\0'; //guarantees null-termination
00071   return id;
00072 }
00073 
00074 std::string Profiler::report() {
00075   char tmp[255];
00076   SectionInfo * infos=getInfos();
00077   sprintf(tmp,"Profiling information since: %f to %f\n",startTime.Value(),TimeET().Value());
00078   std::string ans(tmp);
00079   for(unsigned int i=0; i<sectionsUsed; i++) {
00080     sprintf(tmp,"%s:\n",infos[i].name); ans+=tmp;
00081     unsigned int calls=infos[i].calls;
00082     sprintf(tmp,"\t%d calls\n",calls); ans+=tmp;
00083     if(calls>0) {
00084       sprintf(tmp,"\t%f ms avg\n",infos[i].totalTime.Value()/calls*1000); ans+=tmp;
00085       sprintf(tmp,"\t%f ms exp.avg\n",infos[i].execExpAvg*1000); ans+=tmp;
00086       sprintf(tmp,"\t%f ms avg child time (%f%%)\n",infos[i].childTime.Value()/calls*1000,((int)(infos[i].childTime.Value()/infos[i].totalTime.Value()*1000))/10.0); ans+=tmp;
00087       sprintf(tmp,"\t%f ms avg inter (%f fps)\n",infos[i].totalInterval.Value()/calls*1000,calls/infos[i].totalInterval.Value()); ans+=tmp;
00088       sprintf(tmp,"\t%f ms exp.avg (%f fps)\n",infos[i].interExpAvg*1000,1/infos[i].interExpAvg); ans+=tmp;
00089       ans+="\tExec: ";
00090       for(unsigned int j=0; j<HistSize; j++) {
00091         sprintf(tmp,"%d ",infos[i].execHist[j]);
00092         ans+=tmp;
00093       }
00094       ans+="\n\tInter: ";
00095       for(unsigned int j=0; j<HistSize; j++) {
00096         sprintf(tmp,"%d ",infos[i].interHist[j]);
00097         ans+=tmp;
00098       }
00099       ans+="\n";
00100     }
00101   }
00102   ans+="Bucket distribution (in ms):\n\t0";
00103   for(unsigned int j=0; j<HistSize; j++) {
00104     sprintf(tmp,"<%.3g, ",buckets[j]*1000);
00105     ans+=tmp;
00106   }
00107   ans+="\n";
00108   return ans;
00109 }
00110 
00111 void Profiler::reset() {
00112   SectionInfo * infos=getInfos();
00113   for(unsigned int i=0; i<sectionsUsed; i++)
00114     infos[i].reset();
00115   startTime.Set();
00116 }
00117 
00118 Profiler::Profiler(unsigned int mx)
00119   : curSection(-1U), startTime(), gamma(.85), maxSections(mx), sectionsUsed(0), autoInit()
00120 { }
00121 
00122 unsigned int Profiler::AutoInit::refcount=0;
00123 unsigned int Profiler::AutoInit::totalcount=0;
00124 
00125 Profiler::AutoInit::AutoInit() {
00126   if(totalcount==0)
00127     Profiler::initBuckets();
00128   totalcount++;
00129   refcount++;
00130 }
00131 
00132 Profiler::AutoInit::~AutoInit() { refcount--; }
00133 
00134 void Profiler::setCurrent(Timer& tr) {
00135   SectionInfo& info=getInfos()[tr._id];
00136   tr._parent=curSection;
00137   curSection=tr._id;
00138   info.calls++;
00139   if(info.calls>1) {
00140     TimeET diff=info.lastTime.Age();
00141     info.totalInterval+=diff;
00142     if(info.calls==2)
00143       info.interExpAvg=diff.Value();
00144     else
00145       info.interExpAvg=info.interExpAvg*gamma+(float)diff.Value()*(1-gamma);
00146     if(diff.Value()*1000>HistTime)
00147       info.interHist[HistSize-1]++;
00148     else
00149       info.interHist[getBucket(diff.Value())]++;
00150   }
00151   tr._t.Set(); //do last so profiling code won't throw off timing results (but makes childtime's a little bloated)
00152   info.lastTime=tr._t;
00153 }
00154 
00155 void Profiler::finished(Timer& tr) {
00156   TimeET diff=tr.elapsed(); //do immediately for accuracy
00157   SectionInfo& info=getInfos()[tr._id];
00158   info.totalTime+=diff;
00159   if(tr._parent!=-1U)
00160     getInfos()[tr._parent].childTime+=diff;
00161   //  ASSERT(info.calls!=0,"calls is 0 on finished");
00162   if(info.calls==1)
00163     info.execExpAvg=diff.Value();
00164   else
00165     info.execExpAvg=info.execExpAvg*gamma+(float)diff.Value()*(1-gamma);
00166   if(diff.Value()*1000>HistTime)
00167     info.execHist[HistSize-1]++;
00168   else
00169     info.execHist[getBucket(diff.Value())]++;
00170   //the old way:
00171   //info.execHist[mathutils::log2t((unsigned int)(((1U<<31)/HistTime*2)*diff.Value()))]++;
00172   curSection=tr._parent;
00173 }
00174 
00175 /*! @file
00176  * @brief Implements Profiler, which managers a hierarchy of timers for profiling time spent in code
00177  * @author ejt (Creator)
00178  *
00179  * $Author: ejt $
00180  * $Name: tekkotsu-4_0 $
00181  * $Revision: 1.15 $
00182  * $State: Exp $
00183  * $Date: 2006/07/13 17:25:50 $
00184  */

Tekkotsu v4.0
Generated Thu Nov 22 00:54:55 2007 by Doxygen 1.5.4