00001
00002 #ifndef _GK_PROFILER_CLOCK
00003 #define _GK_PROFILER_CLOCK
00004
00005 #include <string>
00006 #include <map>
00007 #include <vector>
00008 #include <cstdio>
00009 #include <cassert>
00010 #include <limits.h>
00011
00012 #ifdef APPLE_OSX
00013 #include <sys/time.h>
00014
00015 #elif defined WIN32
00016 #include <windows.h>
00017
00018 #else
00019 #include <sys/time.h>
00020 #endif
00021
00022 #include <cstdlib>
00023
00024 namespace gk {
00025
00026 #ifndef WIN32
00027
00028
00029 class ProfilerClock
00030 {
00031
00032 ProfilerClock( const ProfilerClock& );
00033 ProfilerClock& operator=( const ProfilerClock& );
00034
00035 protected:
00036 struct timeval m_start;
00037
00038
00039 ProfilerClock( )
00040 {
00041 gettimeofday(&m_start, NULL);
00042 }
00043
00044
00045 ~ProfilerClock() {}
00046
00047 int delay( const struct timeval& x, const struct timeval& base ) const
00048 {
00049 struct timeval y= base;
00050
00051
00052 if(x.tv_usec < y.tv_usec)
00053 {
00054 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
00055 y.tv_usec -= 1000000 * nsec;
00056 y.tv_sec += nsec;
00057 }
00058
00059 if (x.tv_usec - y.tv_usec > 1000000)
00060 {
00061 int nsec = (x.tv_usec - y.tv_usec) / 1000000;
00062 y.tv_usec += 1000000 * nsec;
00063 y.tv_sec -= nsec;
00064 }
00065
00066 int sec = x.tv_sec - y.tv_sec;
00067 int usec = x.tv_usec - y.tv_usec;
00068
00069 return sec * 1000000 + usec;
00070 }
00071
00072 int get_ticks( )
00073 {
00074 struct timeval ticks;
00075 gettimeofday(&ticks, NULL);
00076
00077
00078
00079
00080
00081
00082 return delay(ticks, m_start);
00083 }
00084
00085 int get_delay( const unsigned int start )
00086 {
00087 int stop= get_ticks();
00088 return stop - start;
00089 }
00090
00091 public:
00092
00093 typedef int Ticks;
00094
00095
00096 static
00097 Ticks getTicks( )
00098 {
00099 return manager().get_ticks();
00100 }
00101
00102
00103 static
00104 int getDelay( const Ticks base )
00105 {
00106 return manager().get_delay(base);
00107 }
00108
00109
00110 static
00111 int delay( const Ticks stop, const Ticks start )
00112 {
00113 return stop - start;
00114 }
00115
00116
00117 static
00118 ProfilerClock& manager( )
00119 {
00120 static ProfilerClock manager;
00121 return manager;
00122 }
00123 };
00124
00125 #else
00126
00127 class ProfilerClock
00128 {
00129
00130 ProfilerClock( const ProfilerClock& );
00131 ProfilerClock& operator=( const ProfilerClock& );
00132
00133 struct clock_val
00134 {
00135 int sec;
00136 int usec;
00137 };
00138
00139 int delay( const clock_val& x, const clock_val& base ) const
00140 {
00141 clock_val y= base;
00142
00143
00144 if(x.usec < y.usec)
00145 {
00146 int nsec = (y.usec - x.usec) / 1000000 + 1;
00147 y.usec -= 1000000 * nsec;
00148 y.sec += nsec;
00149 }
00150
00151 if (x.usec - y.usec > 1000000)
00152 {
00153 int nsec = (x.usec - y.usec) / 1000000;
00154 y.usec += 1000000 * nsec;
00155 y.sec -= nsec;
00156 }
00157
00158 int sec = x.sec - y.sec;
00159 int usec = x.usec - y.usec;
00160
00161 return sec * 1000000 + usec;
00162 }
00163
00164 protected:
00165 clock_val m_start;
00166 LARGE_INTEGER m_last_frequency;
00167
00168 ProfilerClock( )
00169 {
00170 LARGE_INTEGER ticks;
00171 QueryPerformanceCounter(&ticks);
00172
00173 LARGE_INTEGER frequency;
00174 QueryPerformanceFrequency(&frequency);
00175 m_last_frequency= frequency;
00176
00177 m_start.sec= ticks.QuadPart / frequency.QuadPart;
00178
00179 m_start.usec= (ticks.QuadPart % frequency.QuadPart) / (frequency.QuadPart / 1000000);
00180 }
00181
00182 ~ProfilerClock() {}
00183
00184 int get_ticks( )
00185 {
00186 LARGE_INTEGER ticks;
00187 QueryPerformanceCounter(&ticks);
00188
00189 LARGE_INTEGER frequency;
00190 QueryPerformanceFrequency(&frequency);
00191 if(frequency.QuadPart != m_last_frequency.QuadPart)
00192 {
00193 #if VERBOSE
00194 printf("ProfilerClock( ): frequency scaling...\n");
00195 #endif
00196 m_last_frequency= frequency;
00197 }
00198
00199 clock_val stop;
00200 stop.sec= ticks.QuadPart / frequency.QuadPart;
00201
00202 stop.usec= (ticks.QuadPart % frequency.QuadPart) / (frequency.QuadPart / 1000000);
00203 return delay(stop, m_start);
00204 }
00205
00206 int get_delay( const int base )
00207 {
00208 int stop= get_ticks();
00209 return stop - base;
00210 }
00211
00212 public:
00213
00214 typedef int Ticks;
00215
00216 static
00217 Ticks getTicks( )
00218 {
00219 return manager().get_ticks();
00220 }
00221
00222 static
00223 int getDelay( const Ticks base )
00224 {
00225 return manager().get_delay(base);
00226 }
00227
00228 static
00229 int delay( const Ticks stop, const Ticks start )
00230 {
00231 return stop - start;
00232 }
00233
00234 static
00235 ProfilerClock& manager( )
00236 {
00237 static ProfilerClock manager;
00238 return manager;
00239 }
00240 };
00241
00242 #endif
00243
00244
00245
00246 class StatsCounter
00247 {
00248 int *m_stats;
00249 int m_head;
00250 int m_tail;
00251 int m_size;
00252 int m_n;
00253
00254 int m_min;
00255 int m_max;
00256 int m_sum;
00257
00258
00259 StatsCounter( const StatsCounter& );
00260 StatsCounter& operator=( const StatsCounter& );
00261
00262 public:
00263
00264 StatsCounter( const int n= 100 )
00265 :
00266 m_head(0),
00267 m_tail(0),
00268 m_size(n),
00269 m_n(0),
00270 m_min(INT_MAX),
00271 m_max(INT_MIN),
00272 m_sum(0)
00273 {
00274 m_stats= new int[n];
00275 }
00276
00277
00278 ~StatsCounter( )
00279 {
00280 delete [] m_stats;
00281 }
00282
00283
00284 void push( const int value )
00285 {
00286 if(value < m_min)
00287 m_min= value;
00288 if(value > m_max)
00289 m_max= value;
00290
00291 m_sum= m_sum + value;
00292 if(m_n >= m_size)
00293 {
00294
00295 m_head= (m_head + 1) % m_size;
00296 assert(m_head >= 0 && m_head < m_size);
00297 m_n--;
00298 }
00299
00300
00301
00302 m_stats[m_tail]= m_sum;
00303 m_tail= (m_tail + 1) % m_size;
00304 assert(m_tail >= 0 && m_tail < m_size);
00305
00306 m_n++;
00307 assert(m_n <= m_size);
00308 }
00309
00310
00311
00312
00313 void getStats( int *min, float *average, int *max )
00314 {
00315 if(min != NULL)
00316 *min= (m_min != 0) ? m_min : 0;
00317 if(max != NULL)
00318 *max= (m_max != 0) ? m_max : 0;
00319 if(average != NULL)
00320
00321 *average= (m_n != 0) ? (float) (m_stats[(m_tail -1 + m_size) % m_size] - m_stats[m_head]) / (float) m_n : 0.f;
00322 }
00323
00324
00325 int last( ) const
00326 {
00327 const int i= (m_tail -1 + m_size) % m_size;
00328 const int i1= (i -1 + m_size) % m_size;
00329 const int value= m_stats[i] - m_stats[i1];
00330 return value;
00331 }
00332
00333
00334 int statCount( ) const
00335 {
00336 return m_n -1;
00337 }
00338
00339
00340 int stat( const int id ) const
00341 {
00342 if(id < 0 || id >= m_n -1)
00343 return 0;
00344
00345 const int i= (m_head + id +1) % m_size;
00346 const int i1= (i -1 + m_size) % m_size;
00347 return m_stats[i] - m_stats[i1];
00348 }
00349
00350
00351 int write( const std::string& name )
00352 {
00353 FILE *out= fopen(std::string(name+ ".txt").c_str(), "wt");
00354 if(out == NULL)
00355 {
00356 printf("error writing counter data '%s.txt'.\n", name.c_str());
00357 return -1;
00358 }
00359
00360 int min, max;
00361 float av;
00362 getStats(&min, &av, &max);
00363
00364 printf("counter '%s': min %d < %f < max %d, ", name.c_str(), min, av, max);
00365 printf("writing counter history to '%s.txt'.\n", name.c_str());
00366
00367 fprintf(out, "# min %d < %f < max %d\n", min, av, max);
00368 for(int id= 1; id < m_n; id++)
00369 {
00370 const int i= (m_head + id ) % m_size;
00371 const int i1= (i -1 + m_size) % m_size;
00372 const int value= m_stats[i] - m_stats[i1];
00373
00374 fprintf(out, "%d\n", value);
00375 }
00376
00377 fclose(out);
00378 return 0;
00379 }
00380 };
00381
00382
00383
00384
00385 class StatsCounterIO
00386 {
00387
00388 StatsCounterIO( const StatsCounterIO& );
00389 StatsCounterIO& operator=( const StatsCounterIO& );
00390
00391 std::map<std::string, StatsCounter *> m_counters_map;
00392 std::vector<StatsCounter *> m_counters;
00393
00394 StatsCounterIO( ) {}
00395
00396 ~StatsCounterIO( )
00397 {
00398 for(std::map<std::string, StatsCounter *>::iterator
00399 i= m_counters_map.begin(); i != m_counters_map.end(); ++i)
00400 {
00401
00402 assert(i->second != NULL);
00403 i->second->write(i->first);
00404 delete i->second;
00405 }
00406 }
00407
00408 public:
00409
00410 StatsCounter *find( const std::string& name )
00411 {
00412 std::map<std::string, StatsCounter *>::iterator found= m_counters_map.find(name);
00413
00414 if(found == m_counters_map.end())
00415 return NULL;
00416 else
00417 return found->second;
00418 }
00419
00420
00421 StatsCounter *create( const std::string& name, const int n )
00422 {
00423 StatsCounter *counter= new StatsCounter(n);
00424 m_counters_map.insert( std::make_pair( name, counter) );
00425 m_counters.push_back(counter);
00426
00427 return counter;
00428 }
00429
00430
00431 int counterCount( ) const
00432 {
00433 return (int) m_counters.size();
00434 }
00435
00436
00437 StatsCounter *counter( const int id )
00438 {
00439 return m_counters[id];
00440 }
00441
00442
00443 static
00444 StatsCounterIO& manager( )
00445 {
00446 static StatsCounterIO manager;
00447 return manager;
00448 }
00449 };
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 class ScopedTimer
00466 {
00467 ProfilerClock::Ticks m_base;
00468 StatsCounter *m_counter;
00469
00470
00471 ScopedTimer( const ScopedTimer& );
00472 ScopedTimer& operator=( const ScopedTimer& );
00473
00474 ScopedTimer( );
00475
00476 public:
00477
00478 ScopedTimer( const std::string& name, const int n= 100 )
00479 {
00480 StatsCounter *counter= StatsCounterIO::manager().find(name);
00481 if(counter == NULL)
00482 counter= StatsCounterIO::manager().create(name, n);
00483
00484 m_counter= counter;
00485 m_base= ProfilerClock::getTicks();
00486 }
00487
00488
00489 int stop( )
00490 {
00491 int time= ProfilerClock::getDelay(m_base);
00492 if(m_counter != NULL)
00493 m_counter->push(time);
00494 m_counter= NULL;
00495
00496 return time;
00497 }
00498
00499
00500 ~ScopedTimer( )
00501 {
00502 int time= ProfilerClock::getDelay(m_base);
00503 if(m_counter != NULL)
00504 m_counter->push(time);
00505 }
00506 };
00507
00508
00509
00510 class ScopedCounter
00511 {
00512 StatsCounter *m_counter;
00513
00514
00515 ScopedCounter( const ScopedCounter& );
00516 ScopedCounter& operator=( const ScopedCounter& );
00517
00518 ScopedCounter( );
00519
00520 public:
00521
00522 ScopedCounter( const std::string& name, const int n= 100 )
00523 {
00524 StatsCounter *counter= StatsCounterIO::manager().find(name);
00525 if(counter == NULL)
00526 counter= StatsCounterIO::manager().create(name, n);
00527
00528 m_counter= counter;
00529 }
00530
00531
00532 void push( const int value )
00533 {
00534 if(m_counter != NULL)
00535 m_counter->push(value);
00536 }
00537
00538
00539 ~ScopedCounter( ) {}
00540 };
00541
00542
00543
00544 class TimerSummary
00545 {
00546 int m_min;
00547 int m_max;
00548 float m_average;
00549 int m_last;
00550
00551 public:
00552
00553 TimerSummary( const std::string& name )
00554 :
00555 m_min(0),
00556 m_max(0),
00557 m_average(0.f),
00558 m_last(0)
00559 {
00560 StatsCounter *counter= StatsCounterIO::manager().find(name);
00561 if(counter == NULL)
00562 return;
00563
00564 counter->getStats(&m_min, &m_average, &m_max);
00565 m_last= counter->last();
00566 }
00567
00568
00569 ~TimerSummary( ) {}
00570
00571
00572 std::string getSummaryString( ) const
00573 {
00574 char tmp[1024];
00575 sprintf(tmp, "%5dms %3dus (min %5dus < %.3fus < %5dus)", m_last / 1000, m_last % 1000,
00576 m_min, m_average, m_max);
00577 return std::string(tmp);
00578 }
00579 };
00580
00581
00582 class CounterSummary
00583 {
00584 int m_min;
00585 int m_max;
00586 float m_average;
00587 int m_last;
00588
00589 public:
00590
00591 CounterSummary( const std::string& name )
00592 :
00593 m_min(0),
00594 m_max(0),
00595 m_average(0.f),
00596 m_last(0)
00597 {
00598 StatsCounter *counter= StatsCounterIO::manager().find(name);
00599 if(counter == NULL)
00600 return;
00601
00602 counter->getStats(&m_min, &m_average, &m_max);
00603 m_last= counter->last();
00604 }
00605
00606
00607 ~CounterSummary( ) {}
00608
00609
00610 std::string getSummaryString( ) const
00611 {
00612 char tmp[1024];
00613 sprintf(tmp, "%d (min %d < %.3f < %d)", m_last,
00614 m_min, m_average, m_max);
00615 return std::string(tmp);
00616 }
00617 };
00618
00619 }
00620
00621 #endif