00001 #include "Profiler.h"
00002 #include "Util.h"
00003 #include <iomanip>
00004
00005 namespace RenderTools {
00006
00007 #ifdef RT_PROFILER
00008
00009 vector<Profiler *> Profiler::s_profilers;
00010 bool Profiler::s_init = false;
00011 int Profiler::s_numPasses = 0;
00012 int Profiler::s_objectID = 0;
00013 int Profiler::s_maxObjects = 0;
00014 vector< pair< UINT, string > > Profiler::s_counters;
00015 #ifdef RT_NVPERFKIT
00016 NVDataProvider * Profiler::s_dataProvider = NULL;
00017 #endif
00018 bool Profiler::s_doExperiment = false;
00019
00020 #ifdef RT_NVPERFKIT
00021 NVDataProvider::NVDataProvider(){
00022 initialise();
00023 }
00024
00025 void NVDataProvider::initialise(){
00026
00027 for( unsigned int i = 0; i < COUNTER_ENTRY_COUNT; i++ ){
00028 for( unsigned int j = 0; j < BUFFER_ENTRY_COUNT; j++ ){
00029 m_counterValues[i][j] = 0.0;
00030 }
00031 }
00032 m_counterIndexArrayCount = 0;
00033 m_counterValuesRRIndex = 0;
00034 }
00035
00036 unsigned int NVDataProvider::add( unsigned int counterIndex ){
00037 if( NVPMAddCounter( counterIndex ) == NVPM_OK ){
00038 m_counterIndexArray[ m_counterIndexArrayCount++ ] = counterIndex;
00039 return counterIndex;
00040 }
00041 else{
00042 return COUNTER_DISABLED;
00043 }
00044 }
00045
00046 unsigned int NVDataProvider::add( string name ){
00047 unsigned int counterIndex;
00048 if( NVPMGetCounterIndex( ( char * )name.c_str(), &counterIndex ) == NVPM_OK ){
00049 return add( counterIndex );
00050 }
00051 else {
00052 return COUNTER_DISABLED;
00053 }
00054 }
00055
00056 bool NVDataProvider::sample(){
00057 unsigned int i, unused;
00058 UINT64 value, cycles;
00059
00060
00061 NVPMSample( NULL, &unused );
00062
00063
00064 for( i = 0; i < m_counterIndexArrayCount; i++ ){
00065 NVPMGetCounterValue( m_counterIndexArray[ i ], 0, &value, &cycles );
00066 m_counterValues[ i ][ m_counterValuesRRIndex ] = cycles ? ( 100.0f * (float) value / (float) cycles ) : 0.0f;
00067 }
00068
00069 m_counterValuesRRIndex++;
00070 if( m_counterValuesRRIndex >= BUFFER_ENTRY_COUNT ){
00071 m_counterValuesRRIndex = 0;
00072 }
00073
00074 return true;
00075 }
00076
00077 float NVDataProvider::value( unsigned int counterIndex ) {
00078 unsigned int entryIndex, arrayIndex;
00079 float runningTotalValues = 0.0f;
00080
00081
00082 for( arrayIndex = 0; arrayIndex < m_counterIndexArrayCount; arrayIndex++ ){
00083 if( m_counterIndexArray[ arrayIndex ] == counterIndex )
00084 break;
00085 }
00086
00087 if( arrayIndex < m_counterIndexArrayCount ){
00088 for( entryIndex = 0; entryIndex < BUFFER_ENTRY_COUNT; entryIndex++ ){
00089 runningTotalValues += m_counterValues[ arrayIndex ][ entryIndex ] / (float)BUFFER_ENTRY_COUNT;
00090 }
00091 }
00092
00093 return( runningTotalValues );
00094 }
00095 #endif //RT_NVPERFKIT
00096
00097 Profiler::Profiler( string name, string file, int line ){
00098
00099 s_profilers.push_back( this );
00100 m_calls = 0;
00101 m_time = 0.0;
00102
00103 m_name = name;
00104 m_file = basename( ( char * )file.c_str() );
00105 m_line = line;
00106 }
00107
00108 Profiler::~Profiler(){
00109 for( unsigned int i = 0; i < s_profilers.size(); i++ ){
00110 if( s_profilers[ i ] == this ){
00111 s_profilers[ i ] = s_profilers[ s_profilers.size() - 1 ];
00112 s_profilers.pop_back();
00113 break;
00114 }
00115 }
00116 }
00117
00118 void Profiler::begin(){
00119 m_calls++;
00120 m_stopWatch.reset();
00121 }
00122
00123 void Profiler::end(){
00124 m_time += m_stopWatch.lapse();
00125 }
00126
00127 double Profiler::average(){
00128 if( m_calls ){
00129 return( m_time / (double) m_calls );
00130 }
00131 else{
00132 return( 0.0 );
00133 }
00134 }
00135
00136 double Profiler::time(){
00137 return( m_time );
00138 }
00139
00140 int Profiler::calls(){
00141 return( m_calls );
00142 }
00143
00144 string Profiler::name(){
00145 return( m_name );
00146 }
00147
00148 string Profiler::file(){
00149 return( m_file );
00150 }
00151
00152 int Profiler::line(){
00153 return( m_line );
00154 }
00155
00156 void Profiler::dumpAll(){
00157
00158 vector<Profiler *>usedProfilers;
00159 for( unsigned int i = 0; i < s_profilers.size(); i++ ){
00160 if( s_profilers[ i ]->calls() ){
00161 usedProfilers.push_back( s_profilers[ i ] );
00162 }
00163 }
00164
00165 for( unsigned int i = 0; i < usedProfilers.size(); i++ ){
00166 Profiler * p1 = usedProfilers[ i ];
00167 for( unsigned int j = i + 1; j < usedProfilers.size(); j++ ){
00168 Profiler * p2 = usedProfilers[ j ];
00169 if( p2->average() > p1->average() ){
00170 usedProfilers[ j ] = p1;
00171 usedProfilers[ i ] = p2;
00172 i--;
00173 break;
00174 }
00175 }
00176 }
00177 int maxNameLen = 10;
00178 int maxLineLen = 10;
00179 for( unsigned int i = 0; i < usedProfilers.size(); i++ ){
00180 Profiler * p = usedProfilers[ i ];
00181 if( (int)p->name().size() > maxNameLen ){
00182 maxNameLen = (int)p->name().size();
00183 }
00184 string line = p->file() + string(":") + ( p->line() ? toString<int>( p->line() ) : "" );
00185 if( (int)line.size() > maxLineLen ){
00186 maxLineLen = (int)line.size();
00187 }
00188 }
00189 cout << endl;
00190 cout << setfill('.') << setw(maxNameLen + 2) << left << "profiler_name" << setw(maxLineLen + 2)<<"filename:line" << "sec/call (calls)" << endl;
00191 cout << endl;
00192 for( unsigned int i = 0; i < usedProfilers.size(); i++ ){
00193 Profiler * p = usedProfilers[ i ];
00194 if( p->calls() && p->name() != "" ){
00195 string lineString = p->file() + string(":") + ( p->line() ? toString<int>( p->line() ) : "" );
00196 cout << setprecision(4) << setfill('.') << setw(maxNameLen + 2) << left << p->name()<< setw(maxLineLen + 2) << lineString << setw(10) << p->average() << " (" << p->calls() << ")" << endl;
00197 }
00198 }
00199 cout << endl;
00200 }
00201
00202 #ifdef RT_NVPERFKIT
00203
00204 void Profiler::_initialise( bool doExperiment, int numOfObjects ){
00205 s_doExperiment = doExperiment;
00206
00207 if( ! s_init ){
00208 NVPMInit();
00209 s_dataProvider = new NVDataProvider();
00210 s_init = true;
00211 }
00212
00213 if( s_doExperiment ){
00214 s_maxObjects = numOfObjects;
00215 NVPMAllocObjects( s_maxObjects );
00216 NVPMRemoveAllCounters();
00217
00218 NVPMAddCounterByName("2D Bottleneck");
00219 NVPMAddCounterByName("IDX Bottleneck");
00220 NVPMAddCounterByName("GEOM Bottleneck");
00221 NVPMAddCounterByName("ZCULL Bottleneck");
00222 NVPMAddCounterByName("TEX Bottleneck");
00223 NVPMAddCounterByName("ROP Bottleneck");
00224 NVPMAddCounterByName("SHD Bottleneck");
00225 NVPMAddCounterByName("FB Bottleneck");
00226 NVPMAddCounterByName("Primitive Setup Bottleneck");
00227 NVPMAddCounterByName("Rasterization Bottleneck");
00228 NVPMAddCounterByName("GPU Bottleneck");
00229 }
00230 else{
00231 s_dataProvider->initialise();
00232
00233 string name;
00234 UINT index;
00235
00236 name = "gpu_idle"; index = s_dataProvider->add( name );
00237 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00238
00239 name = "vertex_attribute_count"; index = s_dataProvider->add( name );
00240 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00241
00242 name = "culled_primitive_count"; index = s_dataProvider->add( name );
00243 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00244
00245 name = "vertex_shader_busy"; index = s_dataProvider->add( name );
00246 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00247
00248 name = "primitive_count"; index = s_dataProvider->add( name );
00249 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00250
00251 name = "triangle_count"; index = s_dataProvider->add( name );
00252 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00253
00254 name = "vertex_count"; index = s_dataProvider->add( name );
00255 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00256
00257 name = "fast_z_count"; index = s_dataProvider->add( name );
00258 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00259
00260 name = "shaded_pixel_count"; index = s_dataProvider->add( name );
00261 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00262
00263 name = "shader_waits_for_sampler"; index = s_dataProvider->add( name );
00264 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00265
00266 name = "pixel_shader_busy"; index = s_dataProvider->add( name );
00267 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00268
00269 name = "shader_waits_for_rop"; index = s_dataProvider->add( name );
00270 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00271
00272 name = "rop_busy"; index = s_dataProvider->add( name );
00273 if( index != COUNTER_DISABLED )s_counters.push_back( pair<UINT, string>( index, name ) );
00274 }
00275 }
00276
00277 void Profiler::_dumpResult( NVPMRESULT result ){
00278 cout << "result : ";
00279 switch( result ){
00280 case NVPM_ERROR_INVALID_PARAMETER:
00281 cout << "NVPM_ERROR_INVALID_PARAMETER";
00282 break;
00283 case NVPM_ERROR_DRIVER_MISMATCH:
00284 cout << "NVPM_ERROR_DRIVER_MISMATCH";
00285 break;
00286 case NVPM_ERROR_NOT_INITIALIZED:
00287 cout << "NVPM_ERROR_NOT_INITIALIZED";
00288 break;
00289 case NVPM_ERROR_ALREADY_INITIALIZED:
00290 cout << "NVPM_ERROR_ALREADY_INITIALIZED";
00291 break;
00292 case NVPM_ERROR_BAD_ENUMERATOR:
00293 cout << "NVPM_ERROR_BAD_ENUMERATOR";
00294 break;
00295 case NVPM_ERROR_STRING_TOO_SMALL:
00296 cout << "NVPM_ERROR_STRING_TOO_SMALL";
00297 break;
00298 case NVPM_ERROR_INVALID_COUNTER:
00299 cout << "NVPM_ERROR_INVALID_COUNTER";
00300 break;
00301 case NVPM_ERROR_OUT_OF_MEMORY:
00302 cout << "NVPM_ERROR_OUT_OF_MEMORY";
00303 break;
00304 case NVPM_ERROR_NOT_IN_EXPERIMENT:
00305 cout << "NVPM_ERROR_NOT_IN_EXPERIMENT";
00306 break;
00307 case NVPM_ERROR_EXPERIMENT_INCOMPLETE:
00308 cout << "NVPM_ERROR_EXPERIMENT_INCOMPLETE";
00309 break;
00310 case NVPM_ERROR_INVALID_PASS:
00311 cout << "NVPM_ERROR_INVALID_PASS";
00312 break;
00313 case NVPM_ERROR_NOT_IN_PASS:
00314 cout << "NVPM_ERROR_NOT_IN_PASS";
00315 break;
00316 case NVPM_ERROR_IN_PASS:
00317 cout << "NVPM_ERROR_IN_PASS";
00318 break;
00319 case NVPM_ERROR_NOT_IN_OBJECT:
00320 cout << "NVPM_ERROR_NOT_IN_OBJECT";
00321 break;
00322 case NVPM_ERROR_IN_OBJECT:
00323 cout << "NVPM_ERROR_IN_OBJECT";
00324 break;
00325 case NVPM_ERROR_INVALID_OBJECT:
00326 cout << "NVPM_ERROR_INVALID_OBJECT";
00327 break;
00328 case NVPM_ERROR_COUNTER_NOT_ENABLED:
00329 cout << "NVPM_ERROR_COUNTER_NOT_ENABLED";
00330 break;
00331 case NVPM_ERROR_COUNTER_NOT_FOUND:
00332 cout << "NVPM_ERROR_COUNTER_NOT_FOUND";
00333 break;
00334 case NVPM_ERROR_EXPERIMENT_NOT_RUN:
00335 cout << "NVPM_ERROR_EXPERIMENT_NOT_RUN";
00336 break;
00337 case NVPM_ERROR_EXPERIMENT_RUNNING:
00338 cout << "NVPM_ERROR_EXPERIMENT_RUNNING";
00339 break;
00340 case NVPM_ERROR_32BIT_ON_64BIT:
00341 cout << "NVPM_ERROR_32BIT_ON_64BIT";
00342 break;
00343 case NVPM_ERROR_INTERNAL:
00344 cout << "NVPM_ERROR_INTERNAL";
00345 break;
00346 }
00347 cout << endl;
00348 }
00349
00350 void Profiler::_sample(){
00351 if( s_doExperiment ){
00352
00353 }
00354 else{
00355 s_dataProvider->sample();
00356 }
00357 }
00358
00359 void Profiler::_dumpSample( bool verbose ){
00360 if( s_doExperiment ){
00361
00362 if( ! s_objectID ){
00363 s_objectID = 1;
00364 }
00365
00366 UINT64 value = 8, cycle = 0;
00367
00368 for( int i = 0; i < s_objectID && i < s_maxObjects; i++ ){
00369 NVPMRESULT result;
00370
00371 UINT64 big = 0;
00372 float sum = 0.0;
00373 int count = 0;
00374
00375 if( ( result = NVPMGetCounterValueByName( "IDX Bottleneck", i, &value, &cycle ) ) == NVPM_OK && cycle ){
00376 if( verbose )cout << "IDX[" << i << "] : \t\t" << value << endl;
00377 sum += (float)value; count++;
00378 if( value > big )big = value;
00379 }
00380 else{
00381 if( cycle )_dumpResult( result );
00382 }
00383 if( ( result = NVPMGetCounterValueByName( "GEOM Bottleneck", i, &value, &cycle ) ) == NVPM_OK && cycle ){
00384 if( verbose )cout << "GEOM[" << i << "] : \t\t" << value << endl;
00385 sum += (float)value; count++;
00386 if( value > big )big = value;
00387 }
00388 else{
00389 if( cycle )_dumpResult( result );
00390 }
00391 if( ( result = NVPMGetCounterValueByName( "SHD Bottleneck", i, &value, &cycle ) ) == NVPM_OK && cycle ){
00392 if( verbose )cout << "SHD[" << i << "] : \t\t" << value << endl;
00393 sum += (float)value; count++;
00394 if( value > big )big = value;
00395 }
00396 else{
00397 if( cycle )_dumpResult( result );
00398 }
00399 if( ( result = NVPMGetCounterValueByName( "FB Bottleneck", i, &value, &cycle ) ) == NVPM_OK && cycle ){
00400 if( verbose )cout << "FB[" << i << "] : \t\t" << value << endl;
00401 sum += (float)value; count++;
00402 if( value > big )big = value;
00403 }
00404 else{
00405 if( cycle )_dumpResult( result );
00406 }
00407 if( ( result = NVPMGetCounterValueByName( "ROP Bottleneck", i, &value, &cycle ) ) == NVPM_OK && cycle ){
00408 if( verbose )cout << "ROP[" << i << "] : \t\t" << value << endl;
00409 sum += (float)value; count++;
00410 if( value > big )big = value;
00411 }
00412 else{
00413 if( cycle )_dumpResult( result );
00414 }
00415 if( ( result = NVPMGetCounterValueByName( "TEX Bottleneck", i, &value, &cycle ) ) == NVPM_OK && cycle ){
00416 if( verbose )cout << "TEX[" << i << "] : \t\t" << value << endl;
00417 sum += (float)value; count++;
00418 if( value > big )big = value;
00419 }
00420 else{
00421 if( cycle )_dumpResult( result );
00422 }
00423 if( count ){
00424 sum /= (float)count;
00425 }
00426 if( ( result = NVPMGetCounterValueByName("GPU Bottleneck", i, &value, &cycle ) ) == NVPM_OK && cycle ){
00427 char str[1024];
00428 NVPMGetGPUBottleneckName( value, str );
00429 if( verbose )cout << "Bottleneck (" << big << "/" << (int)sum << ", pass " << i << ") : \t" << str << endl;
00430 }
00431 }
00432 if( verbose )cout << endl;
00433 }
00434 else if( verbose ){
00435 for( unsigned int i = 0; i < s_counters.size(); i++ ){
00436 cout << s_counters[ i ].second << " : " << s_dataProvider->value( s_counters[ i ].first ) << endl;
00437 }
00438 cout << endl;
00439 }
00440 }
00441
00442 void Profiler::shutDown(){
00443 NVPMRemoveAllCounters();
00444 NVPMDeleteObjects();
00445 NVPMShutdown();
00446 }
00447 #endif // RT_NVPERFKIT
00448
00449 #else
00450
00451 void ____forced_public_symbol(){}
00452
00453 #endif
00454
00455 };