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
00247 class IStatsUserData
00248 {
00249 protected:
00250 std::string m_name;
00251
00252 public:
00253 IStatsUserData( const std::string& name )
00254 :
00255 m_name(name)
00256 {}
00257
00258 const std::string& name( ) const
00259 {
00260 return m_name;
00261 }
00262
00263 virtual ~IStatsUserData( ) {}
00264 };
00265
00266
00267 class StatsCounter
00268 {
00269 std::vector<IStatsUserData *> m_data;
00270
00271 long long int *m_stats;
00272 int m_head;
00273 int m_tail;
00274 int m_size;
00275 int m_n;
00276
00277 int m_min;
00278 int m_max;
00279 long long int m_sum;
00280
00281
00282 StatsCounter( const StatsCounter& );
00283 StatsCounter& operator=( const StatsCounter& );
00284
00285 public:
00286
00287 StatsCounter( const int n= 100 )
00288 :
00289 m_head(0),
00290 m_tail(0),
00291 m_size(n),
00292 m_n(0),
00293 m_min(INT_MAX),
00294 m_max(INT_MIN),
00295 m_sum(0)
00296 {
00297 m_stats= new long long int[n];
00298 }
00299
00300
00301 ~StatsCounter( )
00302 {
00303 delete [] m_stats;
00304
00305 const int n= m_data.size();
00306 for(int i= 0; i < n; i++)
00307 delete m_data[i];
00308 }
00309
00310
00311 int attachUserData( IStatsUserData *data )
00312 {
00313 if(data == NULL || findUserData(data->name()) != NULL)
00314 return -1;
00315
00316 m_data.push_back(data);
00317 return 0;
00318 }
00319
00320
00321 IStatsUserData *findUserData( const std::string& name )
00322 {
00323 return findUserData(name.c_str());
00324 }
00325
00326
00327 IStatsUserData *findUserData( const char *name )
00328 {
00329 const int n= (int) m_data.size();
00330 for(int i= 0; i < n; i++)
00331 if(m_data[i]->name() == name)
00332 return m_data[i];
00333
00334 return NULL;
00335 }
00336
00337
00338 IStatsUserData *userData( const int id )
00339 {
00340 if(id < 0 || id >= (int) m_data.size())
00341 return NULL;
00342 return m_data[id];
00343 }
00344
00345
00346 void push( const int value )
00347 {
00348 if(value < m_min)
00349 m_min= value;
00350 if(value > m_max)
00351 m_max= value;
00352
00353 m_sum= m_sum + (long long int) value;
00354 if(m_n >= m_size)
00355 {
00356
00357 m_head= (m_head + 1) % m_size;
00358 m_n--;
00359 assert(m_n >= 0);
00360 }
00361
00362
00363 m_stats[m_tail]= m_sum;
00364 m_tail= (m_tail + 1) % m_size;
00365 m_n++;
00366 assert(m_n <= m_size);
00367 }
00368
00369
00370
00371
00372 void getStats( int *min, float *average, int *max ) const
00373 {
00374 if(min != NULL)
00375 *min= m_min;
00376 if(max != NULL)
00377 *max= m_max;
00378
00379 if(average != NULL)
00380
00381 *average= (m_n != 0) ? (float) (m_stats[(m_tail -1 + m_size) % m_size] - m_stats[m_head]) / (float) m_n : 0.f;
00382 }
00383
00384
00385 float average( const unsigned int n= 30 ) const
00386 {
00387 if(n >= (unsigned int) m_n)
00388 return 0.f;
00389
00390 const int i= (m_tail -1 + m_size) % m_size;
00391 const int i1= (i - n + m_size) % m_size;
00392 return (m_stats[i] - m_stats[i1]) / (float) n;
00393 }
00394
00395
00396 int last( ) const
00397 {
00398 const int i= (m_tail -1 + m_size) % m_size;
00399 const int i1= (i -1 + m_size) % m_size;
00400 const long long int value= m_stats[i] - m_stats[i1];
00401 return (int) value;
00402 }
00403
00404
00405 int statCount( ) const
00406 {
00407 return m_n -1;
00408 }
00409
00410
00411 int stat( const int id ) const
00412 {
00413 if(id < 0 || id >= m_n -1)
00414 return 0;
00415
00416 const int i= (m_head + id +1) % m_size;
00417 const int i1= (i -1 + m_size) % m_size;
00418 return (int) (m_stats[i] - m_stats[i1]);
00419 }
00420
00421
00422 int write( const std::string& name ) const
00423 {
00424 FILE *out= fopen(std::string(name+ ".txt").c_str(), "wt");
00425 if(out == NULL)
00426 {
00427 printf("error writing counter data '%s.txt'.\n", name.c_str());
00428 return -1;
00429 }
00430
00431 int min, max;
00432 float av;
00433 getStats(&min, &av, &max);
00434
00435 printf("counter '%s': min %d < %f < max %d, ", name.c_str(), min, av, max);
00436 printf("writing counter history to '%s.txt'.\n", name.c_str());
00437
00438 fprintf(out, "# min %d < %f < max %d\n", min, av, max);
00439 for(int id= 1; id < m_n; id++)
00440 {
00441 const int i= (m_head + id ) % m_size;
00442 const int i1= (i -1 + m_size) % m_size;
00443 const long long int value= m_stats[i] - m_stats[i1];
00444
00445 fprintf(out, "%d\n", (int) value);
00446 }
00447
00448 fclose(out);
00449 return 0;
00450 }
00451 };
00452
00453
00454
00455
00456 class StatsCounterIO
00457 {
00458
00459 StatsCounterIO( const StatsCounterIO& );
00460 StatsCounterIO& operator=( const StatsCounterIO& );
00461
00462 std::map<std::string, StatsCounter *> m_counters_map;
00463 std::vector<StatsCounter *> m_counters;
00464
00465 StatsCounterIO( ) {}
00466
00467 ~StatsCounterIO( )
00468 {
00469 for(std::map<std::string, StatsCounter *>::iterator
00470 i= m_counters_map.begin(); i != m_counters_map.end(); ++i)
00471 {
00472
00473 assert(i->second != NULL);
00474 i->second->write(i->first);
00475 delete i->second;
00476 }
00477 }
00478
00479 public:
00480
00481 StatsCounter *find( const std::string& name )
00482 {
00483 std::map<std::string, StatsCounter *>::iterator found= m_counters_map.find(name);
00484
00485 if(found == m_counters_map.end())
00486 return NULL;
00487 else
00488 return found->second;
00489 }
00490
00491
00492 StatsCounter *create( const std::string& name, const int n )
00493 {
00494 StatsCounter *counter= new StatsCounter(n);
00495 m_counters_map.insert( std::make_pair( name, counter) );
00496 m_counters.push_back(counter);
00497
00498 return counter;
00499 }
00500
00501
00502 int counterCount( ) const
00503 {
00504 return (int) m_counters.size();
00505 }
00506
00507
00508 StatsCounter *counter( const int id )
00509 {
00510 return m_counters[id];
00511 }
00512
00513
00514 std::string getSummaryString( const int n= 30 ) const
00515 {
00516 char tmp[1024];
00517 std::string summary;
00518
00519 for(std::map<std::string, StatsCounter *>::const_iterator
00520 i= m_counters_map.begin(); i != m_counters_map.end(); ++i)
00521 {
00522 assert(i->second != NULL);
00523
00524 const int value= i->second->last();
00525 float av= i->second->average(n);
00526 sprintf(tmp, "%s: %d [%.3f : %d]\n",
00527 i->first.c_str(), value, av, n);
00528
00529 summary.append(tmp);
00530 }
00531
00532 return summary;
00533 }
00534
00535
00536 static
00537 StatsCounterIO& manager( )
00538 {
00539 static StatsCounterIO manager;
00540 return manager;
00541 }
00542 };
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 class ScopedTimer
00559 {
00560 ProfilerClock::Ticks m_base;
00561 StatsCounter *m_counter;
00562
00563
00564 ScopedTimer( const ScopedTimer& );
00565 ScopedTimer& operator=( const ScopedTimer& );
00566
00567 ScopedTimer( );
00568
00569 public:
00570
00571 ScopedTimer( const std::string& name, const int n= 100 )
00572 {
00573 StatsCounter *counter= StatsCounterIO::manager().find(name);
00574 if(counter == NULL)
00575 counter= StatsCounterIO::manager().create(name, n);
00576
00577 m_counter= counter;
00578 m_base= ProfilerClock::getTicks();
00579 }
00580
00581
00582 int stop( )
00583 {
00584 int time= ProfilerClock::getDelay(m_base);
00585 if(m_counter != NULL)
00586 m_counter->push(time);
00587 m_counter= NULL;
00588
00589 return time;
00590 }
00591
00592
00593 ~ScopedTimer( )
00594 {
00595 int time= ProfilerClock::getDelay(m_base);
00596 if(m_counter != NULL)
00597 m_counter->push(time);
00598 }
00599 };
00600
00601
00602
00603 class ScopedCounter
00604 {
00605 StatsCounter *m_counter;
00606
00607
00608 ScopedCounter( const ScopedCounter& );
00609 ScopedCounter& operator=( const ScopedCounter& );
00610
00611 ScopedCounter( );
00612
00613 public:
00614
00615 ScopedCounter( const std::string& name, const int n= 100 )
00616 {
00617 StatsCounter *counter= StatsCounterIO::manager().find(name);
00618 if(counter == NULL)
00619 counter= StatsCounterIO::manager().create(name, n);
00620
00621 m_counter= counter;
00622 }
00623
00624
00625 void push( const int value )
00626 {
00627 if(m_counter != NULL)
00628 m_counter->push(value);
00629 }
00630
00631
00632 ~ScopedCounter( ) {}
00633 };
00634
00635
00636
00637 class TimerSummary
00638 {
00639 int m_min;
00640 int m_max;
00641 float m_average;
00642 int m_last;
00643
00644 public:
00645
00646 TimerSummary( const std::string& name )
00647 :
00648 m_min(0),
00649 m_max(0),
00650 m_average(0.f),
00651 m_last(0)
00652 {
00653 StatsCounter *counter= StatsCounterIO::manager().find(name);
00654 if(counter == NULL)
00655 return;
00656
00657 counter->getStats(&m_min, &m_average, &m_max);
00658 m_last= counter->last();
00659 }
00660
00661
00662 ~TimerSummary( ) {}
00663
00664
00665 std::string getSummaryString( ) const
00666 {
00667 char tmp[1024];
00668 sprintf(tmp, "% 5dms % 4dus (min % 5dus < %.3fus < % 5dus)", m_last / 1000, m_last % 1000,
00669 m_min, m_average, m_max);
00670 return std::string(tmp);
00671 }
00672 };
00673
00674
00675 class CounterSummary
00676 {
00677 int m_min;
00678 int m_max;
00679 float m_average;
00680 int m_last;
00681
00682 public:
00683
00684 CounterSummary( const std::string& name )
00685 :
00686 m_min(0),
00687 m_max(0),
00688 m_average(0.f),
00689 m_last(0)
00690 {
00691 StatsCounter *counter= StatsCounterIO::manager().find(name);
00692 if(counter == NULL)
00693 return;
00694
00695 counter->getStats(&m_min, &m_average, &m_max);
00696 m_last= counter->last();
00697 }
00698
00699
00700 ~CounterSummary( ) {}
00701
00702
00703 std::string getSummaryString( ) const
00704 {
00705 char tmp[1024];
00706 sprintf(tmp, "%d (min %d < %.3f < %d)", m_last,
00707 m_min, m_average, m_max);
00708 return std::string(tmp);
00709 }
00710 };
00711
00712 }
00713
00714 #endif