/*
 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
 * unrestricted use provided that this legend is included on all tape
 * media and as a part of the software program in whole or part.  Users
 * may copy or modify Sun RPC without charge, but are not authorized
 * to license or distribute it to anyone else except as part of a product or
 * program developed by the user.
 * 
 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 * 
 * Sun RPC is provided with no support and without any obligation on the
 * part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 * 
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
 * OR ANY PART THEREOF.
 * 
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even if
 * Sun has been advised of the possibility of such damages.
 * 
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */

#if !defined(lint) && defined(SCCSIDS)
static char sccsid[] = "@(#)stat.c  1.5  90/01/07  Copyr 1988 Sun Micro";
#endif

/*
 * Original algo from Knuth, Vol 2, P216, eq (15) and (16).
 * Modified to suit my purposes,
 *
 * exports:
 *	get_n() returns (int)n | n = number of elements
 *	get_avg() returns (double)n | n = avg of all data
 *	stddev() returns (double)n | n = std deviation
 *
 *	init_data() called to init stuff
 *	print_data() prints all the important statistics
 *	print_real_ave() prints all the important statistics considering
 * 		the wierd out of band data.
 */
#include <stdio.h>
#include <math.h>

static double M, S, sum;
static cur_num;
static int *datap;

extern int bytes;
double sqrt();
double stddev();
void init_data();
void print_data();

add_data(x)
{
	if (cur_num == 0) {
		M = x;
		S = 0;
		sum = 0;
	} else {
		register double oM, oS;

		oM = M;
		oS = S;
		M = oM + (x - oM) / cur_num;
		S = oS + (x - oM) * (x - M);
	}
	sum += x;
	datap[cur_num] = x;
	cur_num++;
}

double
get_avg()
{
	return (sum / cur_num);
}

double
stddev()
{
	if (cur_num <= 1)
		return 0.0;
	return (sqrt(S / (cur_num - 1)));
}

get_n()
{
	return (cur_num);
}

void
init_data(num)
	int num;
{
	cur_num = 0;
	if (datap == NULL)
		datap = (int *)malloc(sizeof (int) * num);
	if (datap == NULL) {
		fatal("No memory for statistics");
	}
}

void
print_data()
{
    printf("\tAverage time = %.2f ms\n\tStandard deviation = %.2f ms\n\tThroughput = %.1f KB/sec\n",
	(float) get_avg()/1000.0, stddev()/1000.0,
	(float) bytes * 1000000 / (1024 * get_avg()));
}

/*
 * Print data about all the entries
 */
print_all_data()
{
	int i;

	printf("Call	Time(ms)	KB/sec\n");
	for (i = 0 ; i < cur_num; i++)
		printf("%3d\t%.2f\t\t%.1f\n", i, datap[i]/1000.0,
			(float) bytes * 1000000 / (1024 * datap[i]));
}
/*
 * Destructive.
 * calculates the real ave taking into account widely varying data.
 * prune data if stdev/avg > 0.25.
 */
print_real_ave()
{
	float avg;
	int i;
	float dev;
	int num;
	float ratio;
	int data_pruned = 0;
	int times_pruned = 0;
	int factor;

	print_data();
prune_again:
	avg = get_avg();
	dev = stddev();
	num = cur_num;
	cur_num = 0;
	ratio = dev/avg;
	if (ratio <= 0.1)
		factor = 3;
	else
		factor = 1;
	for (i = 0; i < num; i++) {
		if ((avg - datap[i] > 0) ||
			(datap[i] - avg < factor * dev) ||
			(ratio <= 0.2 && datap[i] < (1.1 * avg))) {
			add_data(datap[i]);
		} else
			data_pruned++;
	}
	if (((ratio = stddev()/get_avg()) > 0.25) && (times_pruned < 3)) {
		times_pruned++;
		printf("pruning again. stddev/average = %.2f\n", ratio);
		goto prune_again;
	}
	if (data_pruned) {
		printf("Total out of bound entries %d\n", data_pruned);
		printf("After pruning:\n");
		print_data();
	}
}
