/*
**++
**  FACILITY:  SPI
**
**  MODULE DESCRIPTION:
**
**      get the performance information
**
**  AUTHORS:
**
**      Holger Teutsch
**
**  CREATION DATE:  12-Jun-1990
**
**  MODIFICATION HISTORY:
**
**      {@tbs@}...
**--
*/
#include descrip
#include ssdef
#include libdtdef
#include "spi.h"

#define SPI$_MODES	0x1000		/* derived from SPITABLE.MAR */
#define SPI$_FRLIST	0x101C		/* and SYSGETSPI.LIS */
#define SPI$_MOLIST	0x101D
#define SPI$_FAULTS	0x101E
#define SPI$_PREADS	0x101F
#define SPI$_PWRITES	0x1020
#define SPI$_PWRITEIO	0x1021
#define SPI$_PREADIO	0x1022
#define SPI$_DIRIO	0x1036
#define SPI$_BUFIO	0x1037
#define SPI$_PROCS	0x101A
#define SPI$_PROC	0x101B


static int len,
	   procs,
	   freelst,
	   modlst,
	   pfaults,
	   preads,
	   preadio,
	   bufio,
	   dirio,
	   dummy;

#define spi_entry( var, txt, flags ) { &var,0,0,0.0,flags,txt}


/* make extern variables from spi.h real */
int modes[ N_MODES ];		    /* current values */
static int modes0[ N_MODES ];	    /* previous values */
int reset = 1;			    /* start with reset */

spi_value_t spi_values[] =
{
    spi_entry( procs,	"# Procs",	0 ),
    spi_entry( dummy,	"",		VALUE_SEP ),
    spi_entry( freelst,	"Free list",	0 ),
    spi_entry( modlst,	"Mod. list",	0 ),
    spi_entry( pfaults,	"Page faults",	VALUE_RESET | VALUE_RATE ),
    spi_entry( preads,	"Page reads",	VALUE_RESET | VALUE_RATE ),
    spi_entry( preadio, "Page rIO",	VALUE_RESET | VALUE_RATE ),
    spi_entry( dummy,	"",		VALUE_SEP ),
    spi_entry( bufio,	"Bufio",	VALUE_RESET | VALUE_RATE ),
    spi_entry( dirio,	"Dirio",	VALUE_RESET | VALUE_RATE ),
};

int n_spi_values = sizeof( spi_values ) / sizeof( spi_value_t );


/* module local variables */

#define MODE_COUNTERS 8
static struct mode_slot {
    char cpu_id;
    int	counter[ MODE_COUNTERS ];
};

static struct {
    int	num_cpu;
    struct mode_slot slot[ 32 ];    /* max 32 CPUs */
} mode_ticks;

static itmslot spiitm[] =
{
    { sizeof( mode_ticks ), SPI$_MODES, &mode_ticks, 0 },
    { 4, SPI$_FRLIST, &freelst, 0 },
    { 4, SPI$_MOLIST, &modlst, 0 },
    { 4, SPI$_FAULTS, &pfaults, 0 },
    { 4, SPI$_PREADS, &preads, 0 },
    { 4, SPI$_PREADIO,&preadio, 0 },
    { 4, SPI$_BUFIO,  &bufio, 0 },
    { 4, SPI$_DIRIO,  &dirio, 0 },
    { 4, SPI$_PROCS,  &procs, &len },
    { 0, 0, 0 }
};



/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      get_spi
**
**  SIDE EFFECTS:
**
**      global fields updated
**
**--
*/
void get_spi (void)
{
    int i,j,r0,help;
    static struct { long int a,b; } last_time, cur_time, diff_time;
    float delta;
    int *mptr,*mptr0,*mptr1;
    spi_value_t *sptr;

    const int cvtf_mode = LIB$K_DELTA_SECONDS_F;


    sys$gettim ( &cur_time );
    
    r0 = exe$getspi(
	      0,	/* efn */
	      0,	/* csiaddr */
	      0,	/* nodename */
	      &spiitm,	/* item list */
	      0,	/* iosb */
	      0,	/* astaddr */
	      0 );	/* astprm */


    if ( ( r0 & 1 ) == 0 )
    {
        lib$stop( r0 );
    }


  /* summ mode counters for all CPUs */

    for ( i = 1 ; i < mode_ticks.num_cpu ; i++ )
    {
	mptr = mode_ticks.slot[ 0 ].counter;
	mptr1 = mode_ticks.slot[ i ].counter;

        for ( j = 0;  j < MODE_COUNTERS;  j++ )
            *mptr++ += *mptr1++;
    }


  /* compute 'normal' modes */

    mptr = mode_ticks.slot[ 0 ].counter;

    modes[ 0 ] = *mptr - *(mptr+7); mptr++;	/* I - null */
    modes[ 1 ] = *mptr++;			/* MP */
    modes[ 2 ] = *mptr++;			/* K */
    modes[ 3 ] = *mptr++;			/* E */
    modes[ 4 ] = *mptr++;			/* S */
    modes[ 5 ] = *mptr++ + *mptr++;		/* U + C -> U */
    modes[ 6 ] = 100;

    lib$sub_times (		    /* build delta time */
        &cur_time, 
	&last_time, 
        &diff_time );

    lib$cvtf_from_internal_time (   /* convert to seconds */
        &cvtf_mode, 
        &delta,
        &diff_time );

    delta = ( delta < 0.1 ? 1.0 : delta );

    last_time = cur_time;	    /* save last time */


  /* compute mode values = CPU tic rates */

    for ( mptr = modes, mptr0 = modes0;  mptr < &modes[ N_MODES-1 ];)
    {
        int help;
	help = *mptr;
	*mptr = ( help - *mptr0 ) / ( delta * mode_ticks.num_cpu );
	*mptr0++ = help;
	modes[ N_MODES-1 ] -= *mptr++;
    }


  /* compute rates */

    for ( sptr = spi_values;  sptr < &spi_values[ n_spi_values ]; sptr++ )
    {
        int help;
	help = *sptr->value;

	if ( sptr->flags & VALUE_RATE )
	{
	    sptr->rate = ( help - sptr->value1 ) / delta;
	    sptr->value1 = help;
	}

	if ( reset && ( sptr->flags & VALUE_RESET ) ) sptr->value0 = help;

	*sptr->value = help - sptr->value0;
    }

    reset = 0;	/* one shot only */
}
