#include <errno.h> #include <time.h> #include <iostream> #include <fstream> #include <string> using namespace std; #include "p4loga.h" #include "args.h" #include "extremes.h" #include "funcnames.h" #include "pidfunc.h" #include "pidhash.h" #include "timestamp.h" #include "usage.h" #define SVRSTART 1 #define PIDSTART 2 #define PIDCOMPUTE 3 #define PIDFINISH 4 #define UNKNOWN -1 int ParseLine( string line, int iscan, time_t ts, int *ppid, int *pltype, PidFunc **pppidfunc, FuncNames *pfuncnames ) { int ispan; int rc; iscan = iscan + 5; ispan = line.find( " ", iscan + 1 ); *ppid = atoi( line.substr( iscan, ispan - iscan ).c_str() ); iscan = ispan + 1; if( ( ispan = line.find( "@", iscan + 1 ) ) != line.npos ) { *pltype = PIDSTART; *pppidfunc = new PidFunc; if( rc = ( *pppidfunc )->Init( ts, *ppid, line, iscan, ispan, pfuncnames ) ) return rc; } else { if( line.substr( iscan, 9 ) == "completed" ) *pltype = PIDFINISH; else if( line.substr( iscan, 11 ) == "compute end" ) *pltype = PIDCOMPUTE; else if( line.substr( iscan, 15 ) == "server starting" ) *pltype = SVRSTART; else *pltype = UNKNOWN; *pppidfunc = 0; } return 0; } int StartPidFunc( PidFunc *ppidfunc, PidHash *ppidhash ) { int rc; ppidfunc->IncrementRefCount(); if( rc = ppidhash->Insert( ppidfunc ) ) return rc; return 0; } int ComputePidFunc( time_t ts, int pid, PidHash *ppidhash, AllExtremes *pmaxgcomputes, AllExtremes *pmingcomputes ) { PidFunc *ppidfunc; if( ppidfunc = ppidhash->Find( pid, false ) ) { ppidfunc->Compute( ts, pmaxgcomputes, pmingcomputes ); } return 0; } int FinishPidFunc( bool detail, time_t ts, int pid, PidFunc *pnextpidfunc, FuncNames *pfuncnames, PidHash *ppidhash, AllExtremes *pmaxgelapseds, AllExtremes *pmingelapseds ) { PidFunc *ppidfunc; if( ppidfunc = ppidhash->Find( pid, true ) ) { if( !pnextpidfunc || ( ppidfunc->GetUser() == pnextpidfunc->GetUser() && ppidfunc->GetClient() == pnextpidfunc->GetClient() && ppidfunc->GetHost() == pnextpidfunc->GetHost() ) ) { ppidfunc->Finish( ts, pmaxgelapseds, pmingelapseds ); if( detail ) ppidfunc->PrintDetail( pfuncnames ); } if( !ppidfunc->DecrementRefCount() ) delete ppidfunc; } return 0; } int PrintSummary( FuncNames *pfuncnames, PidHash *ppidhash, AllExtremes *maxgcomputes, AllExtremes *mingcomputes, AllExtremes *maxgelapseds, AllExtremes *mingelapseds ) { cout << "\n"; ppidhash->PrintMaxConcurrent( pfuncnames ); cout << "\n"; maxgcomputes->Print( "Global Compute Phase Maximums", pfuncnames ); mingcomputes->Print( "Global Compute Phase Minimums", pfuncnames ); maxgelapseds->Print( "Global Elapsed Maximums", pfuncnames ); mingelapseds->Print( "Global Elapsed Minimums", pfuncnames ); pfuncnames->Print(); return 0; } int ProcessP4log( bool detail, time_t begints, time_t endts, ifstream& p4log ) { string line; int iscan; int rc; time_t ts; int pid; int ltype; PidFunc *ppidfunc; FuncNames funcnames; PidHash pidhash; AllExtremes maxgcomputes; AllExtremes mingcomputes; AllExtremes maxgelapseds; AllExtremes mingelapseds; maxgcomputes.Init( MAXIMUMS, 32 ); mingcomputes.Init( MINIMUMS, 0 ); maxgelapseds.Init( MAXIMUMS, 32 ); mingelapseds.Init( MINIMUMS, 0 ); while( getline( p4log, line ) ) if( ( iscan = line.find( " pid " ) ) != line.npos ) { str2time( line.substr( iscan - 19, 19 ), &ts ); if( difftime( ts, begints ) >= 0 && difftime( endts, ts ) >= 0 ) { if( rc = ParseLine( line, iscan, ts, &pid, <ype, &ppidfunc, &funcnames ) ) return rc; if( ltype == PIDSTART || ltype == PIDFINISH ) { if( rc = FinishPidFunc( detail, ts, pid, ppidfunc, &funcnames, &pidhash, &maxgelapseds, &mingelapseds ) ) return rc; } switch( ltype ) { case PIDSTART: { if( rc = StartPidFunc( ppidfunc, &pidhash ) ) return rc; break; } case PIDCOMPUTE: { if( rc = ComputePidFunc( ts, pid, &pidhash, &maxgcomputes, &mingcomputes ) ) return rc; break; } case SVRSTART: { pidhash.Flush(); break; } } } } if( rc = PrintSummary( &funcnames, &pidhash, &maxgcomputes, &mingcomputes, &maxgelapseds, &mingelapseds ) ) return rc; return 0; } int main( int argc, char **argv ); int main( int argc, char **argv ) { bool usage; bool detail; string p4logfile; time_t begints; time_t endts; int rc; if( rc = ParseArgs( argc, argv, &usage, &detail, &begints, &endts, &p4logfile ) ) return rc; if( usage ) { PrintUsage(); } else { if( rc = PrintArgs( detail, begints, endts, p4logfile ) ) return rc; ifstream p4log( p4logfile.c_str() ); if( p4log ) { if( detail ) cout << "\n"; if( rc = ProcessP4log( detail, begints, endts, p4log ) ) return rc; } else { cout << "Couldn't open p4d server log!\n"; cout << "Perhaps p4loga --help for more information?\n"; return ENOENT; } } return 0; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 4955 | Michael Shields | Abstract out Log class. | ||
#3 | 4630 | Michael Shields |
Throw away garbage in the log resulting from p4d bug 15356. Such garbage will no longer prematurely terminate p4loga. |
||
#2 | 1722 | Michael Shields |
p4loga builds for freebsd4 (play), hpux11 (hell), linux24x86 (duey), and solaris26 (shucks). A bit of porting was required for the hpux11 build (aCC as configured on hell isn't quite up to speed with respect to namespaces). |
||
#1 | 1610 | Michael Shields |
Adding p4d log analyzer concocted by myself. Compiles and executes on Red Hat 6.0, 7.0, and probably a few other operating systems with perhaps a little help. Still needs comments. |