/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident "$Header: munge.c 1.7 89/07/26 $"

/*
 * munge.c
 *
 * Routines here calculate the rates for all stats
 * collected and sum of these rates across disk and ether devices
 */

#include <sys/types.h>
#include <sys/vm.h>
#include <sys/buf.h>
#include <sys/stats_disk.h>
#include <sys/param.h>
#include <sys/clock.h>
#include <sys/fcntl.h>
#include <sys/flock.h>
#include <stdio.h>
#include "sslib.h"

extern ulong	fsreadhit, fswritehit; /* File Sys hit ratios */
extern unsigned deficit;
extern ulong	pgin, pgpgin;
extern ulong	pgout, pgpgout;
extern ulong	freemem, dirtymem;
extern ulong	totalvm;

/*
 * The so macro handles the difference of two unsigned's in the
 * presence of wraparound
 */
#define MAXUNSIGNED	4294967295
#define	so(n,o)		(((n) >= (o)) ? ((n)-(o)) : (MAXUNSIGNED-(o)+(n)+1))

/*
 * The QSUB routine will subtract two quad (64 bit int) values and
 * convert the result into a double. (ie, double = q0 - q1)
 */
double
QSUB(q0, q1)
ulong q0[2], q1[2];
{
	ulong d[2];

	d[0] = q0[0] - q1[0];
	d[1] = q0[1] - q1[1];
	if (d[0] > q0[0])
		d[1]--;
	return(d[1] * 4294967296. + d[0]);
}

munge(sc, vm_old, vm_new, vm_rate, ds_old, ds_new, ds_rate, disk_sum,
	memst_old, memst_new,
	flip, flsp)
	struct ss_cfg *sc;
	struct vmmeter *vm_old;
	struct vmmeter *vm_new;
	struct vmmeter *vm_rate;
	struct disk_stats *ds_old;
	struct disk_stats *ds_new;
	struct disk_stats *ds_rate;
	struct disk_summary *disk_sum;
	struct mem_stats *memst_old, *memst_new;
	struct flckinfo *flip;
	struct flock_stats *flsp;
{
	register int i;
	register double etime;
	register ulong *osp, *nsp, *rsp;
	int j;
	ulong	ticks;

	/*
	 * Calculate time in the interval
	 * must divide by sc->nonline and HZ to get number of seconds.
	 */
	ticks = 0;
	for (i = 0; i < V_CPU_STATES; i++)
		ticks += vm_new->v_time[i] - vm_old->v_time[i];
	ticks /= sc->nonline;
	if (ticks == 0)
		ticks = 1;
	etime = (double)ticks / HZ;

	/*
	 * Calculate the rate for vm stuff
	 */
	rsp = &(vm_rate->v_first);
	osp = &(vm_old->v_first);
	nsp = &(vm_new->v_first);
	for (; rsp <= &(vm_rate->v_last); rsp++, osp++, nsp++) {
		/* the "so" macro handles wrap-around */
		*rsp = (so(*nsp,*osp) / (double)etime) + 0.5;
	}
	/* Convert physical i/o blks to KB */
	vm_rate->v_phreadblks >>= 1;
	vm_rate->v_phwriteblks >>= 1;
	if (vm_rate->v_lread != 0 && 
	    vm_rate->v_lread > vm_rate->v_bread)
		fsreadhit = 100. * (vm_rate->v_lread - vm_rate->v_bread)
					/ vm_rate->v_lread + 0.5;
	else
		fsreadhit = 0;
	if (vm_rate->v_lwrite != 0 &&
	    vm_rate->v_lwrite > vm_rate->v_bwrite)
		fswritehit = 100. * (vm_rate->v_lwrite - vm_rate->v_bwrite)
					/ vm_rate->v_lwrite + 0.5;
	else
		fswritehit = 0;

	/*
	 * Sum the page in/out values from file and from swap.
	 */
	pgin = vm_rate->v_pgin_file + vm_rate->v_pgin_swap;
	pgpgin = vm_rate->v_pgpgin_file + vm_rate->v_pgpgin_swap;
	pgout = vm_rate->v_pgout_file + vm_rate->v_pgout_swap;
	pgpgout = vm_rate->v_pgpgout_file + vm_rate->v_pgpgout_swap;

	/*
	 * Convert memory stats and deficit to 1K units
	 */
#define pgtok(a) ((a)*NBPG/1024)
	freemem = QSUB(memst_new->m_freemem, memst_old->m_freemem);
	freemem = pgtok(freemem / ticks + 0.5);
	dirtymem = QSUB(memst_new->m_dirtymem, memst_old->m_dirtymem);
	dirtymem = pgtok(dirtymem / ticks + 0.5);
	totalvm = pgtok(memst_new->m_totalvm);
	deficit = pgtok(deficit);

	/*
	 * Calculate rate and sum for disk stuff
	 * Note that none of the cylinder and seek distance histogram data
	 * is available.
	 */
	(void) memset((char *)disk_sum, 0, sizeof(struct disk_summary));
	for (i = 0; i < sc->ndisks; i++, ds_old++, ds_new++, ds_rate++) {
		ulong totxfer = 0;
		ulong misc;

                (void) memcpy(ds_rate->ds_name, ds_old->ds_name,
			sizeof(ds_rate->ds_name));
                ds_rate->ds_cyls = ds_old->ds_cyls;
                ds_rate->ds_flags = ds_old->ds_flags;
                misc = ds_new->ds_misc - ds_old->ds_misc;
                ds_rate->ds_misc = misc / etime +0.5;
                ds_rate->ds_resp[0] = ds_new->ds_resp[0] - ds_old->ds_resp[0];
                ds_rate->ds_resp[1] = ds_new->ds_resp[1] - ds_old->ds_resp[1];
                if (ds_rate->ds_resp[0] > ds_new->ds_resp[0])
                        ds_rate->ds_resp[1]--;
                ds_rate->ds_active[0] = ds_new->ds_active[0] -
							ds_old->ds_active[0];
                ds_rate->ds_active[1] = ds_new->ds_active[1] -
							ds_old->ds_active[1];
                if (ds_rate->ds_active[0] > ds_new->ds_active[0])
                        ds_rate->ds_active[1]--;

                for (j = 0; j < B_TYPES; j++) {
			ulong n;

                        n = ds_new->ds_reads[j] - ds_old->ds_reads[j];
                        ds_rate->ds_reads[j] = n / etime + 0.5;
			disk_sum->reads += n;
			totxfer += n;

                        n = ds_new->ds_writes[j] - ds_old->ds_writes[j];
                        ds_rate->ds_writes[j] = n / etime + 0.5;
			disk_sum->writes += n;
			totxfer += n;

                        n = ds_new->ds_rdblks[j] - ds_old->ds_rdblks[j];
                        ds_rate->ds_rdblks[j] = n / etime + 0.5;
			disk_sum->rd_kbytes += n / 2.0 + 0.5;
			disk_sum->kbytes += n / 2.0 + 0.5;

                        n = ds_new->ds_wtblks[j] - ds_old->ds_wtblks[j];
                        ds_rate->ds_wtblks[j] = n / etime + 0.5;
			disk_sum->wt_kbytes += n / 2.0 + 0.5;
			disk_sum->kbytes += n / 2.0 + 0.5;
                }
		disk_sum->xfers += totxfer;
		totxfer += misc;	/* add in misc for qlen calc. */
		/* Average "instantaneous" q length over the interval */
		if (totxfer > 0) {
			ds_rate->ds_cqlen =
				(ds_new->ds_cqlen - ds_old->ds_cqlen) / totxfer;
		} else {
			ds_rate->ds_cqlen = 0;
		}
                for (j = 0; j < DS_QHISTSZ; j++) {
                        ds_rate->ds_qhist[j] = ds_new->ds_qhist[j] - ds_old->ds_qhist[j];
                }
                for (j = 0; j < DS_RTHISTSZ; j++) {
                        ds_rate->ds_resphist[j] = ds_new->ds_resphist[j] -
                                ds_old->ds_resphist[j];
                }
	}
	/*
	 * Finally, convert the disk summary info into rates
	 */
	disk_sum->xfers = disk_sum->xfers / etime + 0.5;
	disk_sum->kbytes = disk_sum->kbytes / etime + 0.5;
	disk_sum->reads = disk_sum->reads / etime + 0.5;
	disk_sum->rd_kbytes = disk_sum->rd_kbytes / etime + 0.5;
	disk_sum->writes = disk_sum->writes / etime + 0.5;
	disk_sum->wt_kbytes = disk_sum->wt_kbytes / etime + 0.5;
	/*
	 * Calculate file locking stats
	 */
	if (flip->recs != 0)
		flsp->lck_ut = flip->reccnt * 100. / (double) flip->recs;
	else
		flsp->lck_ut = 0;
}


perprocrate(sc, old, new, procutil)
	struct ss_cfg *sc;
	register struct vmmeter *old;
	register struct vmmeter *new;
	ulong	*procutil;
{
	register int j;
	register unsigned etime;
	register ulong *up;
	int i;

	for (i = 0; i < sc->Nengine; i++) {
		up = procutil;
		etime = 0;
		for (j = 0; j < V_CPU_STATES; j++, up++) {
			*up = new->v_time[j] - old->v_time[j];
			etime += *up;
		}
		up = procutil;
		if (etime != 0) {
			for (j = 0; j < V_CPU_STATES; j++, up++) {
				*up = (*up / (double)etime) * 100. +0.5;
			}
		}
		new++;
		old++;
		procutil += V_CPU_STATES;
	}
}
