#include <errno.h> #include <time.h> #ifndef NONAMESPACE #include <iostream> #include <fstream> using namespace std; #else #include <iostream.h> #include <fstream.h> #endif #include <string> #include "p4loga.h" #include "extremes.h" #include "funcnames.h" #include "pidfunc.h" #include "pidhash.h" #include "log.h" #include "timestamp.h" #include "outputtype.h" #define SVRSTART 1 #define PIDSTART 2 #define PIDCOMPUTE 3 #define PIDFINISH 4 #define UNKNOWN -1 int Log::SetFilename( string afilename ) { filename = afilename; return 0; } int Log::Open() { logstream.open( filename.c_str() ); if( !logstream ) return errno; return 0; } int Log::Close() { logstream.close(); if( logstream ) return errno; return 0; } int Log::Process( int outputtype, time_t begints, time_t endts ) { string line; int iscan; int rc; time_t ts; int pid; int ltype; PidFunc *ppidfunc; maxgcomputes.Init( MAXIMUMS, 32 ); mingcomputes.Init( MINIMUMS, 0 ); maxgelapseds.Init( MAXIMUMS, 32 ); mingelapseds.Init( MINIMUMS, 0 ); while( getline( logstream, line ) ) { /* * Got a line; process it. */ if( ( iscan = line.find( " pid " ) ) != line.npos ) { /* * Line contains " pid "; this line may be of interest. */ if( iscan < 19 ) { /* * Not enough characters prior to the " pid " for the * expected timestamp. This line is garbage; skip it. */ continue; } /* * Attempt to (quietly) get the timestamp. */ if( str2time( line.substr( iscan - 19, 19 ), true, &ts ) ) { /* * Timestamp is not in the expected format. * This line is garbage; skip it. */ continue; } if( difftime( ts, begints ) >= 0 && difftime( endts, ts ) >= 0 ) { if( rc = ParseLine( line, iscan, ts, &pid, <ype, &ppidfunc ) ) return rc; if( ltype == PIDSTART || ltype == PIDFINISH ) { if( rc = FinishPidFunc( outputtype, ts, pid, ppidfunc ) ) return rc; } switch( ltype ) { case PIDSTART: { if( rc = StartPidFunc( ppidfunc ) ) return rc; break; } case PIDCOMPUTE: { if( rc = ComputePidFunc( ts, pid ) ) return rc; break; } case SVRSTART: { pidhash.Flush(); break; } } } } } if (outputtype != OUTPUT_CSV) { if( rc = PrintSummary() ) return rc; } return 0; } int Log::ParseLine( string line, int iscan, time_t ts, int *ppid, int *pltype, PidFunc **pppidfunc ) { 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, &funcnames ) ) 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 Log::StartPidFunc( PidFunc *ppidfunc ) { int rc; ppidfunc->IncrementRefCount(); if( rc = pidhash.Insert( ppidfunc ) ) return rc; return 0; } int Log::ComputePidFunc( time_t ts, int pid ) { PidFunc *ppidfunc; if( ppidfunc = pidhash.Find( pid, false ) ) { ppidfunc->Compute( ts, &maxgcomputes, &mingcomputes ); } return 0; } int Log::FinishPidFunc( int outputtype, time_t ts, int pid, PidFunc *pnextpidfunc ) { PidFunc *ppidfunc; if( ppidfunc = pidhash.Find( pid, true ) ) { if( !pnextpidfunc || ( ppidfunc->GetUser() == pnextpidfunc->GetUser() && ppidfunc->GetClient() == pnextpidfunc->GetClient() && ppidfunc->GetHost() == pnextpidfunc->GetHost() ) ) { ppidfunc->Finish( ts, &maxgelapseds, &mingelapseds ); if( outputtype == OUTPUT_DETAIL ) ppidfunc->PrintDetail( &funcnames ); if( outputtype == OUTPUT_CSV ) ppidfunc->PrintCSV( &funcnames ); } if( !ppidfunc->DecrementRefCount() ) delete ppidfunc; } return 0; } int Log::PrintSummary() { cout << "\n"; pidhash.PrintMaxConcurrent( &funcnames ); cout << "\n"; maxgcomputes.Print( "Global Compute Phase Maximums", &funcnames ); mingcomputes.Print( "Global Compute Phase Minimums", &funcnames ); maxgelapseds.Print( "Global Elapsed Maximums", &funcnames ); mingelapseds.Print( "Global Elapsed Minimums", &funcnames ); funcnames.Print(); return 0; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 5390 | Shawn Hladky |
modified p4loga: added --csv switch to output a coma-separated variable file identifying every command function recorded. No header or summary info is displayed. This file can be loaded in a spreadsheet application or imported into a database for further analysis. added support to identify the ClientProgram name from the log file. At this point, only server logs for a 2005.1 server have been (minimally) tested. |
||
#1 | 5389 | Shawn Hladky | Branching p4loga for modifications | ||
//guest/michael_shields/src/p4loga/log.cc | |||||
#1 | 4955 | Michael Shields | Abstract out Log class. |