/* mem.c - Computing the data rate of copying in main memory.
   No consideration is given to page alignment of memory, or to
   lines in the cache.
   Compile with
      % gcc -o mem mem.c -lm
   And run with  
      % mem
***************************************************************/

#include <sys/time.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define BUFSIZE 256*1024         // size of source and of destination areas 
#define MAX_SIZE 128*BUFSIZE	// Amount of data transfererred in one iteration
#define N_ITERATIONS 10		// Number of iterations

long int time_elapsed(struct timeval time1, struct timeval time2);

int
main(int argc, char *argv[])
{
    static char src[BUFSIZE], dst[BUFSIZE];
    int iter;
    int total;
    int n;

    double avgs, stddevs;
    struct timeval time_start, time_end;
    long int t;
    double sum = 0.0;
    double bitRate [N_ITERATIONS]; 
    int k;
    int h;
    int elemsize;

    /* We test memory copy with various sizes of the unit copied, 4, 8, 
       16, 32, 64, 128, 256, 512, 1024 bytes */
    for (k = 0, elemsize = 4; k<9; ++k, elemsize = elemsize + elemsize) {
       int nelems = BUFSIZE/elemsize;

	sum = 0;
        for (iter = 0; iter<N_ITERATIONS; ++iter) { // at each size N_ITERATIONs
	     //	printf("Starting iteration %d\n", iter);
	     total = 0;
	     if (gettimeofday(&time_start, NULL) != 0) {
	      	  perror("gettimeofday");
	      	  exit(1);
	     }
	     for (; (total < MAX_SIZE); total += BUFSIZE) {
	 	char *srcp = src;
		char *dstp = dst;
		for (h = 0; h < nelems; ++h) {
		   memcpy((void *)dstp, (void *)srcp, elemsize);
		   srcp += elemsize;
		   dstp += elemsize;
		}
	     }
	     if (gettimeofday(&time_end, NULL) != 0) {
	      	  perror("gettimeofday");
	      	  exit(1);
	     }
	     t = time_elapsed(time_start, time_end);
	     bitRate[iter] = MAX_SIZE*8.0/(1.0*t);
	     //	printf("\tbandwidth is %f Mbps\n", bitRate[iter]);
	     sum += bitRate[iter];
	  }
         avgs = sum/N_ITERATIONS;
         stddevs = 0.0;
         for (h = 0; h<N_ITERATIONS; ++h)
	          stddevs += (bitRate[h] - avgs)*(bitRate[h] - avgs);
         stddevs = sqrt(stddevs/N_ITERATIONS);
         printf("Size = %d, Average: %f Mbps, Standard Deviation: %f\n", elemsize, avgs,
	              stddevs);
    }
    return 0;
} 


long int time_elapsed(struct timeval time1, struct timeval time2)
{
  return (1000000*(time2.tv_sec-time1.tv_sec) + (time2.tv_usec-time1.tv_usec));
}

