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

Tekkotsu v2.4.1
Generated Tue Aug 16 16:32:48 2005 by Doxygen 1.4.4