#include "copyright.h"
/****************************************************************** 
 *
 * builtinfn.c
 *
 *     Definitions of built-in functions that are available
 *     for Nlv's formulas. ( See 'calc.l' and 'calc.y' )
 *
 * $Author: mstoufer $
 * $Source: /home/g2/src/projects/NetLogger/src/nlv/old/builtinfn.c,v $
 * $RCSfile: builtinfn.c,v $
 * $Revision: 1.1.1.1 $
 * $Locker:  $
 * $Date: 2000/12/05 19:52:33 $
 *
 ****************************************************************** 
 */
static char rcsid[] = "$Id: builtinfn.c,v 1.1.1.1 2000/12/05 19:52:33 mstoufer Exp $";

#include "builtinfn.h"

/* globals */
extern Nlv_State nlvState;
/* Tcl interpreter, defined in mytkAppInit.c */
extern Tcl_Interp *Et_Interp;

/* internal functions */
int ShowLandT( void );

/* mean */
void Nlv_CalcMean ( Nlv_cc calc, Nlv_AData *d ) { return; }
void Nlv_ClearMean( Nlv_cc calc, int huh ) { return; }

/* standard deviation */
void Nlv_CalcStddev ( Nlv_cc calc, Nlv_AData *d ) { return; }
void Nlv_ClearStddev( Nlv_cc calc, int huh) { return; }

/* latency and throughput */
void Nlv_ShowCalculations()
{
  if ( Nlv_anGetAnalysisMode( nlvState.an ) )
    ShowLandT();
}

int Nlv_InitLatency( Nlv_an anclass )
{
  Nlv_cc lat;

  lat = Nlv_ccNew();
  Nlv_ccSetName( lat, LATENCY_STR );
  Nlv_ccSetFunctions( lat, Nlv_CalcLatency, Nlv_ClearLatency );
  Nlv_ccSetParam( lat, 1, 3 );
  Nlv_ccSetCapacity( lat, NLV_MAX_KS_CLIENTS * NLV_MAX_KEYSETS );
  Nlv_ccSetKeysetShow( lat, nlvState.ky );
  Nlv_anAddCalc( anclass, lat );
}
int Nlv_InitThroughput( Nlv_an anclass )
{
  Nlv_cc thru;

  thru = Nlv_ccNew();
  Nlv_ccSetName( thru, THROUGHPUT_STR );
  Nlv_ccSetFunctions( thru, Nlv_CalcThroughput, Nlv_ClearThroughput );
  Nlv_ccSetParam( thru, 1, 1 );
  Nlv_ccSetCapacity( thru, NLV_MAX_KS_CLIENTS );
  Nlv_ccSetKeysetShow( thru, nlvState.ky );
  Nlv_anAddCalc( anclass, thru );
}

/* result    = r[0]
 * prevEvent = r[1]
 * prevStart = r[2]
 * prevTime  = r[3]
 */
void Nlv_CalcLatency( Nlv_cc calc, Nlv_AData *data )
{
  int    evnt = data->gdata->event;
  int    clnt = data->gdata->clIndex;
  double time = data->gdata->time;
  Nlv_CalcResult *r;

  if ( data->gdata->graphType != NLV_LINE )
    return;

  r = Nlv_ccGetResult( calc, clnt );
  if ( !r ) {
    return;
  }
  if ( evnt <= r[1] ) {
    if ( r[2] < 0 ) {
      r[2] = time;
    }
    else {
      r[0] +=  (r[3] - r[2]);
      r[2] = time;
      Nlv_ccAddIter(calc, clnt);
    }
  }
  r[3]  = time;
  r[1]  = evnt;
}
/* result    = r[0]
 * prevEvent = r[1]
 */
void Nlv_CalcThroughput( Nlv_cc calc, Nlv_AData *data )
{
  int    evnt = data->gdata->event;
  int    clnt = data->gdata->clIndex;
  double time = data->gdata->time;
  Nlv_CalcResult *r;
  int blockLoc;
  double blockSize;

  if ( data->gdata->graphType != NLV_LINE )
    return;

  r = Nlv_ccGetResult( calc, clnt );
  if ( !r ) {
    return;
  }
  if ( evnt <= r[1] ) {
    Nlv_ccAddIter(calc, clnt);
    blockLoc = Nlv_MatchField( data->fields, "DPSS.BSZ" );
    if ( blockLoc >= 0 )
      if ( TCL_OK == Tcl_GetDouble( Et_Interp,
				    FIELD_VAL( data->fields, blockLoc ), 
				    &blockSize ) )
	r[0] += blockSize;
  }
  r[1]  = evnt;
}

void Nlv_ClearLatency( Nlv_cc calc, int num )
{
  int i;
  int s;
  Nlv_CalcResult *r;

  for ( i=0; i < num; i++ ) {
    r = Nlv_ccGetResult( calc, i );
    r[0] = 0.;
    r[1] = 9999.;
    r[2] = -1.;
    r[3] = 0.;
  }
}
void Nlv_ClearThroughput( Nlv_cc calc, int num )
{
  int i;
  Nlv_CalcResult *r;

  for ( i=0; i < num; i++ ) {
    r = Nlv_ccGetResult( calc, i );
    r[0] = 0.;
    r[1] = 9999.;
  }
}
/*
 *----------------------------------------------------------------------
 *
 * ShowLandT -- Show throughput and latency data.
 *
 * Input:
 *
 * Calls:
 *
 * Algorithm: print it
 *
 *----------------------------------------------------------------------
 */
#define NLV_CNUM 2
int ShowLandT( void )
{
  Nlv_cc calc;                 /* Holder for calculation */
  int n;                       /* Number of clients */
  int i, j;                    /* Loop counters */
  Nlv_CalcResult *r[NLV_CNUM]; /* Calculation results, per-calculation */
  long iter[NLV_CNUM];         /* Number of iterations, per-calculation */
  char *widgetName;            /* Name of widget to display in */
  char *clientName;            /* Name of client */
  char buf[ 1024 ];            /* Buffer for TCL command string */
  char *nm;                    /* Limited-width client name */
  Nlv_Bounds *bb;              /* Bounds of calculation window */
  int nameWidth;               /* Allowed name width */
  double thru, thruSum;        /* Throughput, throughput total */
  double sfactor;              /* Scale factor for times */
  double bytes2mbits;          /* Conversion between bytes, megabits */
  Nlv_Client *clptr;           /* Pointer to current client */

  n = Nlv_clGetNumClients( nlvState.cl );
  bytes2mbits = (double)(8 / 1000000.);
  widgetName = Tcl_GetVar2( Et_Interp, "widget", "landt", TCL_GLOBAL_ONLY );
  if ( TCL_OK != Tcl_GetInt( Et_Interp, Tcl_GetVar2(Et_Interp, "param","STAT,NameWid",TCL_GLOBAL_ONLY ),&nameWidth) )
    nameWidth = 16;
  nm = (char *)malloc( (nameWidth + 1) * sizeof(char) );

  /* Put time window into title frame */
  sfactor = Nlv_grGetScaleFactor( nlvState.gr );
  bb      = Nlv_anGetWindow( nlvState.an );
  sprintf( buf, "%s.t.title delete 0 end", widgetName );
  NLV_SAFE_EVAL( Et_Interp, buf );
  if ( sfactor == 1000. )
    sprintf( buf, "%s.t.title insert 0 \"Analysis window  =  %.1lf ms   ( %.1lf .. %.1lf ) \"",
	     widgetName,
	     ( bb->x[1] - bb->x[0] ) * sfactor,
	     Nlv_grGraphTime( nlvState.gr, bb->x[0]),
	     Nlv_grGraphTime( nlvState.gr, bb->x[1])  );
  else
    sprintf( buf, "%s.t.title insert 0 \"Analysis window  =  %.3lf s   ( %.3lf .. %.3lf ) \"",
	     widgetName,
	     ( bb->x[1] - bb->x[0] ),
	     Nlv_grGraphTime( nlvState.gr, bb->x[0]),
	     Nlv_grGraphTime( nlvState.gr, bb->x[1])  );
  
  NLV_SAFE_EVAL( Et_Interp, buf );
  /* Put headers at top of value lists */
  for ( i=0; i < 4 ; i++ ) {
    sprintf( buf, "%s.b.lat%d delete 0 end", widgetName, i );
    NLV_SAFE_EVAL( Et_Interp, buf );
    switch( i ) {
    case 0: sprintf( buf, "%s.b.lat0 insert end \"Name\"", widgetName ); 
      break;
    case 1: sprintf( buf, "%s.b.lat1 insert end \"Count\"", widgetName );
      break;
    case 2: 
      if ( sfactor == 1000. )
	sprintf( buf, "%s.b.lat2 insert end \"Avg Latency (ms)\"", widgetName );
      else
      sprintf( buf, "%s.b.lat2 insert end \"Avg Latency (s)\"", widgetName );
      break;
    case 3: sprintf( buf, "%s.b.lat3 insert end \"Throughput (Mbit/s)\"", widgetName ); 
      break;
    }
    NLV_SAFE_EVAL( Et_Interp, buf );
    sprintf( buf, "%s.b.lat%d insert end \"-----------------------------------\"", widgetName, i );
    NLV_SAFE_EVAL( Et_Interp, buf );
  }

  /* Fill in data */
  thruSum = 0.;
  /* i = client index */
  for ( i=0; i < n; i ++ ) {
    /* j = calculation index */
    for (j=0; j < NLV_CNUM; j++ ) {
      calc = Nlv_anGetCalc( nlvState.an, j );
      r[j]    = Nlv_ccGetResult( calc, i );
      iter[j] = Nlv_ccGetIter( calc, i );
    }
    /*
     * Is there any calculated data in the window for this client? 
     */
    if ( iter[0] + iter[1] != 0 ) {
      /* 
       * Get the client record from the data structure 
       */
      clptr = Nlv_clGetClientRecord( nlvState.cl, i );
      /* 
       * Get the client name and data
       */
      clientName = Nlv_clGetClientName( clptr );
      if ( strlen(clientName) > nameWidth ) {
	strncpy( nm, clientName, nameWidth );
      }
      else
	strcpy( nm, clientName );
      /*
       * Display information on screen
       */
      sprintf( buf, "%s.b.lat0 insert end \"%-11s\"", widgetName, nm );
      NLV_SAFE_EVAL( Et_Interp, buf );      
      sprintf( buf, "%s.b.lat1 insert end \"%-5ld\"", widgetName, ((iter[0] > 0) ? iter[0] : iter[1]) );
      NLV_SAFE_EVAL( Et_Interp, buf );
      if ( iter[0] > 0 )
	sprintf( buf, "%s.b.lat2 insert end \"%-10.4lf\"",widgetName, (double)(*r[0]) / iter[0] * sfactor );
      else
	sprintf( buf, "%s.b.lat2 insert end \"--\"", widgetName );
      NLV_SAFE_EVAL( Et_Interp, buf );
      if ( iter[1] > 0 ) {
	thru = (double)(*r[1]) / (bb->x[1] - bb->x[0]) * bytes2mbits * sfactor;
	sprintf( buf, "%s.b.lat3 insert end \"%-10.3lf\"", widgetName,
		 thru);
      }
      else {
	thru = 0.;
	sprintf( buf, "%s.b.lat3 insert end \"--\"", widgetName );
      }
      NLV_SAFE_EVAL( Et_Interp, buf );      
      /*
       *  Increment throughput total
       */
      thruSum += thru;
    }
  }
  sprintf( buf, "%s.b.lat3 insert end \"============\"", widgetName );
  NLV_SAFE_EVAL( Et_Interp, buf );
  sprintf( buf, "%s.b.lat3 insert end \"%-10.3lf\"", widgetName,
	   thruSum);
  NLV_SAFE_EVAL( Et_Interp, buf );

  free( nm );
  return TCL_OK;
}
#undef NLV_CNUM
