/********************************************************************************* /* File: /* ORDERPRO.CPP /* Author: /* Max-H. Windisch, SDE-T /* Date: /* October 1996 /* Summary: /* Utility for sorting results generated by profile.h: /* 1) sorts all nodes by start time (requires "history" profiling) /* 2) extracts the time difference between two specified nodes /* /* (c) Copyright 1996 Microsoft-Softimage Inc. /********************************************************************************/ // includes #define MAX_PROFILING_ENABLED #include #pragma warning(push, 3) #include #include #include #include #include #include #pragma warning (pop) #include //namespace std //{ // #include //} // global markers CString g_oThreadId( "@@ThreadId=" ); CString g_oRange( "@@Range=[origin(" ); CString g_oRangeDuration( ",duration(" ); CString g_oDeltaToPrevious( "@@DeltaToPrev=" ); // the profiling line class CProfLine { protected: DWORD m_dwThreadId; CMaxLargeInteger m_oStartStamp; CString m_oLine; public: CProfLine( DWORD dwThreadId = 0, const CMaxLargeInteger &roStamp = CMaxLargeInteger(), const CString &roLine = CString() ) : m_dwThreadId( dwThreadId ) , m_oStartStamp( roStamp ) , m_oLine( roLine ) { }; bool operator <( const CProfLine &o ) const { return m_oStartStamp < o.m_oStartStamp; }; void FOutput( ostream &os, const CProfLine &roPrevious ) const { CMaxLargeInteger frequency; CMaxLargeInteger dtp = m_oStartStamp - roPrevious.m_oStartStamp; ::QueryPerformanceFrequency( frequency ); os << "[" << g_oThreadId << setw( 4 ) << m_dwThreadId << ", "; os << g_oDeltaToPrevious << setw( 14 ) << dtp.dFInSecondsF( frequency ) << "s]"; os << m_oLine << endl; }; }; // the file parsers base class class CResultParser { protected: ifstream m_is; public: CResultParser( const CString &roInputFileName ) : m_is( (PCTSTR)roInputFileName ){}; virtual void FExecute() { FParse(); FOutputResults(); }; protected: virtual void FParse() { const unsigned long len = 400; CString line; LPTSTR buf; int i = 0; while ( !m_is.eof() ) { buf = line.GetBufferSetLength( len ); m_is.getline( buf, len ); line.ReleaseBuffer( -1 ); FProcessLine( line, i++ ); } }; virtual void FProcessLine( const CString &roLine, int nLineNumber ) = 0; virtual void FOutputResults() = 0; protected: bool bFGetThreadIdFromLine( const CString &roLine, DWORD &dwThreadId ) { int i; if ( ( i = roLine.Find( g_oThreadId ) ) >= 0 ) { CString s = roLine.Mid( i + g_oThreadId.GetLength() ); dwThreadId = atoi( s ); cout << "new thread=" << dwThreadId << endl; return true; } // Note: don't touch dwThreadId return false; }; bool bFGetRangeFromLine( const CString &roLine, CMaxLargeInteger &roStart, CMaxLargeInteger &roDuration ) { int i; CString s1; if ( ( i = roLine.Find( g_oRange ) ) >= 0 ) { s1 = roLine.Mid( i + g_oRange.GetLength() ); FExtractLargeInteger( s1, roStart ); if ( ( i = roLine.Find( g_oRangeDuration ) ) >= 0 ) { s1 = roLine.Mid( i + g_oRangeDuration.GetLength() ); FExtractLargeInteger( s1, roDuration ); } return true; } // Note: don't touch roStart or roDuration return false; }; void FExtractLargeInteger( const CString &roLineSegment, CMaxLargeInteger &roL ) { int delim1 = roLineSegment.Find( ';' ); CString s2 = roLineSegment.Left( delim1 ); int delim2 = roLineSegment.Find( ')' ); CString s3 = roLineSegment.Mid( delim1 + 1, delim2 - delim1 - 1 ); roL = CMaxLargeInteger( atoi( s2 ), atoi( s3 ) ); }; }; // the sorting parser class CSortByStartTime : public CResultParser { protected: typedef std::less PLCompare; typedef std::set PLSet; protected: PLSet m_oSet; DWORD m_dwThreadId; CString m_oOutputFileName; public: CSortByStartTime( const CString &roInputFileName, const CString &roOutputFileName ) : CResultParser( roInputFileName ) , m_dwThreadId( 0 ) , m_oOutputFileName( roOutputFileName ){}; protected: virtual void FProcessLine( const CString &roLine, int ) { CMaxLargeInteger l1, l2; if ( bFGetThreadIdFromLine( roLine, m_dwThreadId ) ); else if ( bFGetRangeFromLine( roLine, l1, l2 ) ) m_oSet.insert( CProfLine( m_dwThreadId, l1, roLine ) ); }; virtual void FOutputResults() { ofstream os( m_oOutputFileName, ios::out | ios::ate ); PLSet::const_iterator j, k; for ( k = j = m_oSet.begin(); m_oSet.end() != j; j++ ) { ( *j ).FOutput( os, ( *k ) ); k = j; } cout << "Done!" << endl; }; }; // the delta parser class CComputeDelta : public CResultParser { protected: int m_nLine1, m_nLine2; CString m_oLine1, m_oLine2; public: CComputeDelta( const CString &roInputFileName, int nLine1, int nLine2 ) : CResultParser( roInputFileName ) , m_nLine1( nLine1 ) , m_nLine2( nLine2 ){}; protected: virtual void FProcessLine( const CString &roLine, int nLineNumber ) { if ( nLineNumber == m_nLine1 ) m_oLine1 = roLine; if ( nLineNumber == m_nLine2 ) m_oLine2 = roLine; }; virtual void FOutputResults() { CMaxLargeInteger l1, l2, l3, l4; if ( bFGetRangeFromLine( m_oLine1, l1, l2 ) && bFGetRangeFromLine( m_oLine2, l3, l4 ) ) { CMaxLargeInteger frequency; ::QueryPerformanceFrequency( frequency ); l3 = l3 + l4; cout << endl; cout << "Delta in seconds between the lines below was " << CMaxLargeInteger( l3 - l1 ).dFInSecondsF( frequency ) << endl; cout << endl; cout << m_oLine1 << endl; cout << endl; cout << m_oLine2 << endl; } else cout << "No result." << endl; cout << "Done!" << endl; }; }; // the little app int __cdecl main( int argc, char *argv[] ) { bool bHandled = true; cout << "MINIPROFILER output flattener." << endl; // try to handle the command if ( argc >= 4 ) { CString command( argv[ 1 ] ); command.MakeLower(); if ( CString( "sort" ) == command ) CSortByStartTime( CString( argv[ 2 ] ), CString( argv[ 3 ] ) ).FExecute(); else if ( CString( "diff" ) == command && argc >= 5 ) CComputeDelta( CString( argv[ 2 ] ), atoi( argv[ 3 ] ), atoi( argv[ 4 ] ) ).FExecute(); else bHandled = false; } else bHandled = false; // give some help if the command was not handled if ( !bHandled ) { cout << endl; cout << "Please enter one of the following sets of arguments:" << endl; cout << endl; cout << " 1) the keyword + the input_result_file + the output_result_file" << endl; cout << " comment: outputs a file where nodes are sorted by start time;" << endl; cout << " requires an input file generated with history" << endl; cout << endl; cout << " 2) the keyword + the input_result_file + line_number_1 + line_number_2" << endl; cout << " comment: returns the delta t covered by those 2 lines" << endl; cout << endl; return 0; } return 0; }