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 #warning Note: Ignore warning on next line (sorry!)
00009 unsigned int Profiler::infosOffset=offsetof(ProfilerOfSize<1>,infos);
00010
00011
00012
00013
00014
00015 Profiler::Timer::Timer(unsigned int id, Profiler* prof) : _prof(prof), _id(id), _parent(-1U), _t(0L) {
00016 if(_prof!=NULL)
00017 _prof->setCurrent(*this);
00018 }
00019
00020 Profiler::Timer::~Timer() {
00021 if(_prof!=NULL)
00022 _prof->finished(*this);
00023 }
00024
00025 void Profiler::Timer::setID(unsigned int id, Profiler* prof) {
00026 _id=id;
00027 _prof=prof;
00028 if(_prof!=NULL)
00029 _prof->setCurrent(*this);
00030 }
00031
00032 Profiler::SectionInfo::SectionInfo()
00033 : totalTime(0L),lastTime(0L),totalInterval(0L),childTime(0L),execExpAvg(0),interExpAvg(0),calls(0)
00034 {
00035 name[0]='\0';
00036 for(unsigned int j=0; j<HistSize; j++)
00037 execHist[j]=interHist[j]=0;
00038 }
00039
00040 void Profiler::SectionInfo::reset() {
00041 totalTime.Set(0L);
00042 lastTime.Set();
00043 totalInterval.Set(0L);
00044 childTime.Set(0L);
00045 execExpAvg=0;
00046 interExpAvg=0;
00047 for(unsigned int j=0; j<HistSize; j++)
00048 execHist[j]=interHist[j]=0;
00049 calls=0;
00050 }
00051
00052 void Profiler::initBuckets() {
00053 float g=HistTime/pow(HistSize,HistCurve)/1000;
00054 for(unsigned int i=1; i<=HistSize; i++)
00055 buckets[i-1]=g*pow(i,HistCurve);
00056 }
00057
00058 unsigned int Profiler::getNewID(const char* name) {
00059 ASSERTRETVAL(sectionsUsed<maxSections,"Too many sections registered (increase ProfilerOfSize<MaxSections>)",-1U);
00060 SectionInfo * infos=getInfos();
00061 #ifdef DEBUG
00062 for(unsigned int i=0; i<sectionsUsed; i++)
00063 ASSERTRETVAL(strncmp(infos[i].name,name,MaxSectionNameLen-1)!=0,"Already using name " << name,-1U);
00064 #endif
00065 unsigned int id=sectionsUsed++;
00066 strncpy(infos[id].name,name,MaxSectionNameLen-1);
00067 infos[id].name[MaxSectionNameLen-1]='\0';
00068 return id;
00069 }
00070
00071 std::string Profiler::report() {
00072 char tmp[255];
00073 SectionInfo * infos=getInfos();
00074 sprintf(tmp,"Profiling information since: %f to %f\n",startTime.Value(),TimeET().Value());
00075 std::string ans(tmp);
00076 for(unsigned int i=0; i<sectionsUsed; i++) {
00077 sprintf(tmp,"%s:\n",infos[i].name); ans+=tmp;
00078 unsigned int calls=infos[i].calls;
00079 sprintf(tmp,"\t%d calls\n",calls); ans+=tmp;
00080 if(calls>0) {
00081 sprintf(tmp,"\t%f ms avg\n",infos[i].totalTime.Value()/calls*1000); ans+=tmp;
00082 sprintf(tmp,"\t%f ms exp.avg\n",infos[i].execExpAvg*1000); ans+=tmp;
00083 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;
00084 sprintf(tmp,"\t%f ms avg inter (%f fps)\n",infos[i].totalInterval.Value()/calls*1000,calls/infos[i].totalInterval.Value()); ans+=tmp;
00085 sprintf(tmp,"\t%f ms exp.avg (%f fps)\n",infos[i].interExpAvg*1000,1/infos[i].interExpAvg); ans+=tmp;
00086 ans+="\tExec: ";
00087 for(unsigned int j=0; j<HistSize; j++) {
00088 sprintf(tmp,"%d ",infos[i].execHist[j]);
00089 ans+=tmp;
00090 }
00091 ans+="\n\tInter: ";
00092 for(unsigned int j=0; j<HistSize; j++) {
00093 sprintf(tmp,"%d ",infos[i].interHist[j]);
00094 ans+=tmp;
00095 }
00096 ans+="\n";
00097 }
00098 }
00099 ans+="Bucket distribution (in ms):\n\t0";
00100 for(unsigned int j=0; j<HistSize; j++) {
00101 sprintf(tmp,"<%.3g, ",buckets[j]*1000);
00102 ans+=tmp;
00103 }
00104 ans+="\n";
00105 return ans;
00106 }
00107
00108 void Profiler::reset() {
00109 SectionInfo * infos=getInfos();
00110 for(unsigned int i=0; i<sectionsUsed; i++)
00111 infos[i].reset();
00112 startTime.Set();
00113 }
00114
00115 Profiler::Profiler(unsigned int mx)
00116 : curSection(-1U), startTime(), gamma(.85), maxSections(mx), sectionsUsed(0)
00117 { }
00118
00119
00120 void Profiler::setCurrent(Timer& tr) {
00121 SectionInfo& info=getInfos()[tr._id];
00122 tr._parent=curSection;
00123 curSection=tr._id;
00124 info.calls++;
00125 if(info.calls>1) {
00126 TimeET diff=info.lastTime.Age();
00127 info.totalInterval+=diff;
00128 if(info.calls==2)
00129 info.interExpAvg=diff.Value();
00130 else
00131 info.interExpAvg=info.interExpAvg*gamma+(float)diff.Value()*(1-gamma);
00132 if(diff.Value()*1000>HistTime)
00133 info.interHist[HistSize-1]++;
00134 else
00135 info.interHist[getBucket(diff.Value())]++;
00136 }
00137 tr._t.Set();
00138 info.lastTime=tr._t;
00139 }
00140
00141 void Profiler::finished(Timer& tr) {
00142 TimeET diff=tr.elapsed();
00143 SectionInfo& info=getInfos()[tr._id];
00144 info.totalTime+=diff;
00145 if(tr._parent!=-1U)
00146 getInfos()[tr._parent].childTime+=diff;
00147
00148 if(info.calls==1)
00149 info.execExpAvg=diff.Value();
00150 else
00151 info.execExpAvg=info.execExpAvg*gamma+(float)diff.Value()*(1-gamma);
00152 if(diff.Value()*1000>HistTime)
00153 info.execHist[HistSize-1]++;
00154 else
00155 info.execHist[getBucket(diff.Value())]++;
00156
00157
00158 curSection=tr._parent;
00159 }
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170