#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/timeb.h>

#define MAXBSIZE (1024*1024*4)
#define LOOPTIME 2.0

typedef unsigned int ui;

long readtime(void);
long read_test(ui);
void build_buffer(int, int);

ui *buf=NULL;

long readtime()
	{
	struct timeb tb;
	static unsigned long timeref=0;

	ftime(&tb);

	if (timeref==0) {timeref=tb.time; }

	tb.time -= timeref;
	tb.time *= 1000; tb.time += tb.millitm;
	return(tb.time);
	}

main()
	{
	double t,wps;
	int str;
	ui count,buflen;
	int pcount=0;
	char strbuf[10];

	buf = (ui *)malloc(MAXBSIZE * sizeof(ui *));
	if (buf==NULL)
	   {
	   printf("Cannot allocate enough memory\n");
	   exit(0);
	   }

	/* Start with a block of 256 words, each word is of type (ui *) */
	build_buffer(256,1);
	count=8;
	printf("Calibrating..."); fflush(stdout);
	do
	   {
	   count *= 2;
	   t = (double) read_test(count) / 1000.0;
	   }
	while(t < 2);

	printf("LoopCount = %d (%3.1lf Seconds)\n",count, t);
	fflush(stdout);

	count = (ui)((double)count * LOOPTIME / t);
	for(buflen=256; buflen<MAXBSIZE; buflen*=4)
	   {
	   printf("\nBuffersize = %u words (%ukb)\n",
		buflen,buflen * sizeof(ui *)/1024);

	   for(str=1; str<buflen; str*=2) printkb(str);

	   putchar('\n'); fflush(stdout);
	   for(str=1; str<buflen; str*=2)
	   	{
	   	build_buffer(buflen,str);

	   	while(1)
	      	   {
	      	   t = (double) read_test(count) / 1000.0;
	      	   if (t<1.0) count*=3; else break;
	      	   }
	
	   	wps = (double)(count) / t;
	   	printf("%3d ", (int)(1.0e9 / wps)); fflush(stdout);

	   	count = (ui)((double)count * LOOPTIME / t);
	   	}
	   putchar('\n');
	   }
	}

long read_test(ui count)
	{
	long t1;
	register ui *o,i=0;

	o=(ui *)buf[0];
	t1=readtime(); while(i<count)
	   	{
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
		o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o); o=(ui *)(*o);
 		i+=64;
	   	}
	return(readtime()-t1);
	}

void
build_buffer(int size, int stridelen)
	{
	ui i;

	for(i=0; i<(size-stridelen); i+=stridelen)
		buf[i]=(ui)&buf[i+stridelen];
	buf[i] = (ui)&buf[0];
	}

printkb(ui val)
	{
	char strbuf[32];
	char c=0;

	if (val>=(1024*1024)) { c='M'; val /= (1024*1024); }
	else if (val>=1024) { c='k'; val /= 1024; }

	sprintf(strbuf,"%d%c",val,c);
	if (val>64 && c) {strbuf[2]=c; strbuf[3]=0;}
	printf("%3s ",strbuf);
	}
