//include <stdio.h>
//include <stdlib.h>
//include <string.h>
//include <unistd.h>
//include <sys/time.h>
//include "meminfo.h"

//int main(int argc, char *argv[]) {
void * memcpy ( void * destination, const void * source, size_t num );


int membandwidth(){
        //printf ( "argv[1] = %s\n", argv[1] );
        //printf ( "argv[2] = %s\n", argv[2] );
	//int empty1;
	//int size1;
	//int size2;
	//size1 = atoi (argv[1]);
	//printf ( "size1: %d\n", size1);
        //printf ( "sizeof int: %d\n", sizeof(int));
	//int output;
        struct timeval starttime,endtime;
        double te, test1, test2, test3;
        register long t, t2;
	//pthread_mutex_lock (&mutex1); 
	//double memtotal = meminfo();
	//double memtotal = 
	//memtotal = memtotal / 1024 / 20;
	//memtotal = .5;
	int long_size=sizeof(long);
	//printf("long size: %d\n", long_size);
	register long asize = memtotal * 1024 * 1024 / long_size;
	register long array_bytes=asize*long_size;
        register long block_size;
	register long *a;
	register long *b;
	//a=calloc(1610612736, 4);
	memtotal /= 2;
	printf ("Running Memory Bandwidth Tests:\n\n");
	//allocate 1200MB a peice (2.4GB total) two zero-initialized memory blocks
	printf ( "\tallocating %lfMB a peice (%lfMB total) two zero-initialized memory blocks\n\n", memtotal, memtotal*2); 
	//gettimeofday(&starttime, NULL);
	a=calloc(asize, long_size);
	b=calloc(asize, long_size);
	//memset ((void*) a, '\0', sizeof (a));
	//memset ((void*) b, '\0', sizeof (b));
	//gettimeofday(&endtime, NULL);
	//te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	//printf ( "\tTime: %lfMB/s\n", memtotal*2/te);

/*
//system("free -m");
	//write data to allocated memory
	printf ( "change all values of allocated memory 1 element at a time\n");
	gettimeofday(&starttime, NULL);
        for(t=0; t<asize; t++) {
                a[t]=0xaa;
		b[t]=0xab;
        }
	gettimeofday(&endtime, NULL);
	te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	printf ( "\tTime: %lfMB/s\n", memtotal*2/te);
//system("free -m");
	//copy array a to array b
	printf ( "copy array a to array b\n");
	gettimeofday(&starttime, NULL);
	memcpy(b,a,array_bytes);
	gettimeofday(&endtime, NULL);
	te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	printf ( "\tTime: %lfMB/s\n", memtotal/te);
//system("free -m");
	//copy array a to array b in steps
	//1MB block size

*/
	printf ( "\tcopying array a to array b in progessive steps of %lfMB\n", memtotal/64);
	block_size= memtotal/64 * 1024 * 1024 / long_size;
	gettimeofday(&starttime, NULL);
	for(t=0; t<array_bytes; t+=block_size) {
        	mempcpy(b,a,t);
        }
	gettimeofday(&endtime, NULL);
        te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
        
	t2 = 0;
        for(t=0; t<array_bytes; t+=block_size) {
               t2+=t; 
        }
	
	test1 = (t2/1024/1024)/te;
	printf ( "\t\tResult: %lfMB/s\n\n", test1*2);

//system("free -m");
	//32MB block size
	printf ( "\tcopying array a to array b in progressive steps of %lfMB\n", memtotal/18);
        block_size=memtotal/18 * 1024 * 1024 / long_size;
	gettimeofday(&starttime, NULL);
        for(t=0; t<array_bytes; t+=block_size) {
                mempcpy(b,a,t);
        }
        gettimeofday(&endtime, NULL); 
        te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
        t2 = 0;
        for(t=0; t<array_bytes; t+=block_size) {
               t2+=t;
        }
	test2 = (t2/1024/1024)/te;
        printf ( "\t\tResult: %lfMB/s\n\n", test2*2);




        printf ( "\tcopying array a to array b in progressive steps of %lfMB\n", memtotal/4);
        block_size=memtotal/4 * 1024 * 1024 / long_size;
        gettimeofday(&starttime, NULL);
        for(t=0; t<array_bytes; t+=block_size) {
                mempcpy(b,a,t);
        }
        gettimeofday(&endtime, NULL);
        te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
        t2 = 0;
        for(t=0; t<array_bytes; t+=block_size) {
               t2+=t;
        }
        test3 = (t2/1024/1024)/te;
        printf ( "\t\tResult: %lfMB/s\n\n", test3*2);





/*
//system("free -m");
	//copy array a to array b 1 element at a time "dumb test"
	printf ( "copy array a to array b 1 element at a time (dumb test)\n");
	gettimeofday(&starttime, NULL);
        for(t=0; t<asize; t++) {
        	b[t]=a[t];
        }
        gettimeofday(&endtime, NULL);
        te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
	printf ( "\tTime: %lfMB/s\n", memtotal/te);
//system("free -m");

*/
	//free arrays
	printf ( "\tfreeing arrays\n\n");
	//gettimeofday(&starttime, NULL);
	free (a);
	free (b);
        //gettimeofday(&endtime, NULL);
        //te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
        //printf ( "\tTime: %lf\n", te);
//system("free -m");


	printf ("\taverage read+write mem bandwidth %lfMB/s\n\n", ((test1*2)+(test2*2)+(test3*2))/3);
	printf ( "\tdone.\n\n");

	//size2 = 1024 / 4; 
	//int array1[(size1*1024)/sizeof(int)];

	//int array1[268435456];
	//size2 = sizeof(array1);
	//printf ( "array1: %lf\n", sizeof(array1));
	//sleep (240);

return 0;	
}
