00001 00002 /*************************************************************************************************** 00003 ** 00004 ** Real-Time Hierarchical Profiling for Game Programming Gems 3 00005 ** 00006 ** by Greg Hjelstrom & Byon Garrabrant 00007 ** 00008 ***************************************************************************************************/ 00009 00010 // Credits: The Clock class was inspired by the Timer classes in 00011 // Ogre (www.ogre3d.org). 00012 00013 00014 00015 #ifndef QUICK_PROF_H 00016 #define QUICK_PROF_H 00017 00018 //To disable built-in profiling, please comment out next line 00019 //#define BT_NO_PROFILE 1 00020 #ifndef BT_NO_PROFILE 00021 00022 #include "btScalar.h" 00023 #include "btAlignedAllocator.h" 00024 #include <new> 00025 00026 00027 00028 00029 //if you don't need btClock, you can comment next line 00030 #define USE_BT_CLOCK 1 00031 00032 #ifdef USE_BT_CLOCK 00033 #ifdef __CELLOS_LV2__ 00034 #include <sys/sys_time.h> 00035 #include <sys/time_util.h> 00036 #include <stdio.h> 00037 #endif 00038 00039 #if defined (SUNOS) || defined (__SUNOS__) 00040 #include <stdio.h> 00041 #endif 00042 00043 #if defined(WIN32) || defined(_WIN32) 00044 00045 #define USE_WINDOWS_TIMERS 00046 #define WIN32_LEAN_AND_MEAN 00047 #define NOWINRES 00048 #define NOMCX 00049 #define NOIME 00050 #ifdef _XBOX 00051 #include <Xtl.h> 00052 #else 00053 #include <windows.h> 00054 #endif 00055 #include <time.h> 00056 00057 #else 00058 #include <sys/time.h> 00059 #endif 00060 00061 #define mymin(a,b) (a > b ? a : b) 00062 00064 class btClock 00065 { 00066 public: 00067 btClock() 00068 { 00069 #ifdef USE_WINDOWS_TIMERS 00070 QueryPerformanceFrequency(&mClockFrequency); 00071 #endif 00072 reset(); 00073 } 00074 00075 ~btClock() 00076 { 00077 } 00078 00080 void reset() 00081 { 00082 #ifdef USE_WINDOWS_TIMERS 00083 QueryPerformanceCounter(&mStartTime); 00084 mStartTick = GetTickCount(); 00085 mPrevElapsedTime = 0; 00086 #else 00087 #ifdef __CELLOS_LV2__ 00088 00089 typedef uint64_t ClockSize; 00090 ClockSize newTime; 00091 //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); 00092 SYS_TIMEBASE_GET( newTime ); 00093 mStartTime = newTime; 00094 #else 00095 gettimeofday(&mStartTime, 0); 00096 #endif 00097 00098 #endif 00099 } 00100 00103 unsigned long int getTimeMilliseconds() 00104 { 00105 #ifdef USE_WINDOWS_TIMERS 00106 LARGE_INTEGER currentTime; 00107 QueryPerformanceCounter(¤tTime); 00108 LONGLONG elapsedTime = currentTime.QuadPart - 00109 mStartTime.QuadPart; 00110 00111 // Compute the number of millisecond ticks elapsed. 00112 unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / 00113 mClockFrequency.QuadPart); 00114 00115 // Check for unexpected leaps in the Win32 performance counter. 00116 // (This is caused by unexpected data across the PCI to ISA 00117 // bridge, aka south bridge. See Microsoft KB274323.) 00118 unsigned long elapsedTicks = GetTickCount() - mStartTick; 00119 signed long msecOff = (signed long)(msecTicks - elapsedTicks); 00120 if (msecOff < -100 || msecOff > 100) 00121 { 00122 // Adjust the starting time forwards. 00123 LONGLONG msecAdjustment = mymin(msecOff * 00124 mClockFrequency.QuadPart / 1000, elapsedTime - 00125 mPrevElapsedTime); 00126 mStartTime.QuadPart += msecAdjustment; 00127 elapsedTime -= msecAdjustment; 00128 00129 // Recompute the number of millisecond ticks elapsed. 00130 msecTicks = (unsigned long)(1000 * elapsedTime / 00131 mClockFrequency.QuadPart); 00132 } 00133 00134 // Store the current elapsed time for adjustments next time. 00135 mPrevElapsedTime = elapsedTime; 00136 00137 return msecTicks; 00138 #else 00139 00140 #ifdef __CELLOS_LV2__ 00141 uint64_t freq=sys_time_get_timebase_frequency(); 00142 double dFreq=((double) freq) / 1000.0; 00143 typedef uint64_t ClockSize; 00144 ClockSize newTime; 00145 SYS_TIMEBASE_GET( newTime ); 00146 //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); 00147 00148 return (unsigned long int)((double(newTime-mStartTime)) / dFreq); 00149 #else 00150 00151 struct timeval currentTime; 00152 gettimeofday(¤tTime, 0); 00153 return (currentTime.tv_sec - mStartTime.tv_sec) * 1000 + 00154 (currentTime.tv_usec - mStartTime.tv_usec) / 1000; 00155 #endif //__CELLOS_LV2__ 00156 #endif 00157 } 00158 00161 unsigned long int getTimeMicroseconds() 00162 { 00163 #ifdef USE_WINDOWS_TIMERS 00164 LARGE_INTEGER currentTime; 00165 QueryPerformanceCounter(¤tTime); 00166 LONGLONG elapsedTime = currentTime.QuadPart - 00167 mStartTime.QuadPart; 00168 00169 // Compute the number of millisecond ticks elapsed. 00170 unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / 00171 mClockFrequency.QuadPart); 00172 00173 // Check for unexpected leaps in the Win32 performance counter. 00174 // (This is caused by unexpected data across the PCI to ISA 00175 // bridge, aka south bridge. See Microsoft KB274323.) 00176 unsigned long elapsedTicks = GetTickCount() - mStartTick; 00177 signed long msecOff = (signed long)(msecTicks - elapsedTicks); 00178 if (msecOff < -100 || msecOff > 100) 00179 { 00180 // Adjust the starting time forwards. 00181 LONGLONG msecAdjustment = mymin(msecOff * 00182 mClockFrequency.QuadPart / 1000, elapsedTime - 00183 mPrevElapsedTime); 00184 mStartTime.QuadPart += msecAdjustment; 00185 elapsedTime -= msecAdjustment; 00186 } 00187 00188 // Store the current elapsed time for adjustments next time. 00189 mPrevElapsedTime = elapsedTime; 00190 00191 // Convert to microseconds. 00192 unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime / 00193 mClockFrequency.QuadPart); 00194 00195 return usecTicks; 00196 #else 00197 00198 #ifdef __CELLOS_LV2__ 00199 uint64_t freq=sys_time_get_timebase_frequency(); 00200 double dFreq=((double) freq)/ 1000000.0; 00201 typedef uint64_t ClockSize; 00202 ClockSize newTime; 00203 //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); 00204 SYS_TIMEBASE_GET( newTime ); 00205 00206 return (unsigned long int)((double(newTime-mStartTime)) / dFreq); 00207 #else 00208 00209 struct timeval currentTime; 00210 gettimeofday(¤tTime, 0); 00211 return (currentTime.tv_sec - mStartTime.tv_sec) * 1000000 + 00212 (currentTime.tv_usec - mStartTime.tv_usec); 00213 #endif//__CELLOS_LV2__ 00214 #endif 00215 } 00216 00217 private: 00218 #ifdef USE_WINDOWS_TIMERS 00219 LARGE_INTEGER mClockFrequency; 00220 DWORD mStartTick; 00221 LONGLONG mPrevElapsedTime; 00222 LARGE_INTEGER mStartTime; 00223 #else 00224 #ifdef __CELLOS_LV2__ 00225 uint64_t mStartTime; 00226 #else 00227 struct timeval mStartTime; 00228 #endif 00229 #endif //__CELLOS_LV2__ 00230 00231 }; 00232 00233 #endif //USE_BT_CLOCK 00234 00235 00236 00237 00239 class CProfileNode { 00240 00241 public: 00242 CProfileNode( const char * name, CProfileNode * parent ); 00243 ~CProfileNode( void ); 00244 00245 CProfileNode * Get_Sub_Node( const char * name ); 00246 00247 CProfileNode * Get_Parent( void ) { return Parent; } 00248 CProfileNode * Get_Sibling( void ) { return Sibling; } 00249 CProfileNode * Get_Child( void ) { return Child; } 00250 00251 void CleanupMemory(); 00252 void Reset( void ); 00253 void Call( void ); 00254 bool Return( void ); 00255 00256 const char * Get_Name( void ) { return Name; } 00257 int Get_Total_Calls( void ) { return TotalCalls; } 00258 float Get_Total_Time( void ) { return TotalTime; } 00259 00260 protected: 00261 00262 const char * Name; 00263 int TotalCalls; 00264 float TotalTime; 00265 unsigned long int StartTime; 00266 int RecursionCounter; 00267 00268 CProfileNode * Parent; 00269 CProfileNode * Child; 00270 CProfileNode * Sibling; 00271 }; 00272 00274 class CProfileIterator 00275 { 00276 public: 00277 // Access all the children of the current parent 00278 void First(void); 00279 void Next(void); 00280 bool Is_Done(void); 00281 bool Is_Root(void) { return (CurrentParent->Get_Parent() == 0); } 00282 00283 void Enter_Child( int index ); // Make the given child the new parent 00284 void Enter_Largest_Child( void ); // Make the largest child the new parent 00285 void Enter_Parent( void ); // Make the current parent's parent the new parent 00286 00287 // Access the current child 00288 const char * Get_Current_Name( void ) { return CurrentChild->Get_Name(); } 00289 int Get_Current_Total_Calls( void ) { return CurrentChild->Get_Total_Calls(); } 00290 float Get_Current_Total_Time( void ) { return CurrentChild->Get_Total_Time(); } 00291 00292 // Access the current parent 00293 const char * Get_Current_Parent_Name( void ) { return CurrentParent->Get_Name(); } 00294 int Get_Current_Parent_Total_Calls( void ) { return CurrentParent->Get_Total_Calls(); } 00295 float Get_Current_Parent_Total_Time( void ) { return CurrentParent->Get_Total_Time(); } 00296 00297 protected: 00298 00299 CProfileNode * CurrentParent; 00300 CProfileNode * CurrentChild; 00301 00302 CProfileIterator( CProfileNode * start ); 00303 friend class CProfileManager; 00304 }; 00305 00306 00308 class CProfileManager { 00309 public: 00310 static void Start_Profile( const char * name ); 00311 static void Stop_Profile( void ); 00312 00313 static void CleanupMemory(void) 00314 { 00315 Root.CleanupMemory(); 00316 } 00317 00318 static void Reset( void ); 00319 static void Increment_Frame_Counter( void ); 00320 static int Get_Frame_Count_Since_Reset( void ) { return FrameCounter; } 00321 static float Get_Time_Since_Reset( void ); 00322 00323 static CProfileIterator * Get_Iterator( void ) 00324 { 00325 00326 return new CProfileIterator( &Root ); 00327 } 00328 static void Release_Iterator( CProfileIterator * iterator ) { delete ( iterator); } 00329 00330 static void dumpRecursive(CProfileIterator* profileIterator, int spacing); 00331 00332 static void dumpAll(); 00333 00334 private: 00335 static CProfileNode Root; 00336 static CProfileNode * CurrentNode; 00337 static int FrameCounter; 00338 static unsigned long int ResetTime; 00339 }; 00340 00341 00344 class CProfileSample { 00345 public: 00346 CProfileSample( const char * name ) 00347 { 00348 CProfileManager::Start_Profile( name ); 00349 } 00350 00351 ~CProfileSample( void ) 00352 { 00353 CProfileManager::Stop_Profile(); 00354 } 00355 }; 00356 00357 00358 #define BT_PROFILE( name ) CProfileSample __profile( name ) 00359 00360 #else 00361 00362 #define BT_PROFILE( name ) 00363 00364 #endif //#ifndef BT_NO_PROFILE 00365 00366 00367 00368 #endif //QUICK_PROF_H 00369 00370
1.6.1