#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"
#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( bool detail, 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( detail, 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( 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( bool detail, 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( detail )
ppidfunc->PrintDetail( &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;
}