/**********************************************************************
 * This file is trying to run a collective number of experiments and
 * prints their result to the standard output in a comprehensive
 * way
 * Redirection of  the output to a specific file is needed
 * for collecting results
 *********************************************************************/


#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <iostream.h>
#include <fstream.h>

const unsigned int KB = 1024;
const unsigned int MB = (1024*1024);
const unsigned int SECTORSIZE = 8*KB;
const unsigned int INITIALSIZE = 50;
const unsigned int INCREMENT = 50;
const unsigned int ENDSIZE = 250;
const unsigned int CHUNK = MB;
const unsigned int SIZE = 100;

int currentExperiment;

void LogError(int ExpNumber) {
  printf("\nError in Experiment %d\n", ExpNumber);
  printf(strerror(errno));
  printf("\n");
  exit(1);
}

void PrintRate(struct timeval tvBefore, struct timeval tvAfter, int ReadSize) {
  struct timeval tvDiff;
  float rate, timeInSeconds;

  tvDiff.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec;
  tvDiff.tv_usec = tvAfter.tv_usec - tvBefore.tv_usec;
  if (tvDiff.tv_usec < 0) { //adjust for usecs
    tvDiff.tv_usec += 1000000;
    tvDiff.tv_sec--;
  }
  
  timeInSeconds = tvDiff.tv_sec+(float)tvDiff.tv_usec/1000000;
  rate = ReadSize/MB/timeInSeconds;
  
  //output the results
  printf("%d\t\t\t%f\n", ReadSize/MB, rate);    
}
  
//****************************************
// FS Write with Unlink

int Experiment1() {
  char *buffer, *buf;
  unsigned int offset;
  int StartWriteSize = INCREMENT*MB, StepWriteSize = INCREMENT*MB, EndWriteSize = ENDSIZE*MB, WriteSize,
    fd, j, k;
  struct timeval tvBefore, tvAfter;  //will hold the time difference
  bool alternate = true;

  currentExperiment = 1;
  printf("\nExperiment #%d\n", currentExperiment);
  printf("Sequential write to filesystem (buffer cache disabled with 
unlink)\n");
  printf("Size in MB\t\t\tRate\n");

  //allocate buffer
  buffer = new char[CHUNK+SECTORSIZE];

  //align buffer
  offset = (unsigned int)buffer;

  if (offset % SECTORSIZE) { //not aligned
    buf = buffer + (SECTORSIZE - offset % SECTORSIZE);
  }    
  else {
    buf = buffer;
  }
  
  //loop incrementing the read size each time
  for (WriteSize = StartWriteSize; WriteSize <= EndWriteSize; WriteSize += StepWriteSize) {
    //open the disk file
    //reopening each time you write will always reset to the begining of the 
    //disk, so you don't have to lseek

    fd=open("/mnt/scsi_c/736Project/write_file", O_CREAT | O_WRONLY );
    if (fd < 0) {
      LogError(currentExperiment);
    }
    
    //start the timer
    if (gettimeofday(&tvBefore, NULL) == -1) {
      LogError(currentExperiment);
    }
    
    for(j=0; j< (WriteSize/CHUNK); j++) {
      //write the chunk of data
      k=write(fd, buf, CHUNK);
      if (k < 0) {
	LogError(currentExperiment);
      }
    }

    //stop the timer
    if (gettimeofday(&tvAfter, NULL) == -1) {
      LogError(currentExperiment);
    }
    
    
    PrintRate(tvBefore, tvAfter, WriteSize);
  //  fsync(fd); //note the fsync is after end of timing     
    close(fd);  //close the file
   unlink("/mnt/scsi_c/736Project/write_file");  //delete the file  
  }
  
  printf("\nExperiment #%d ended Successfully\n", currentExperiment);
 
  //deallocate the buffer
  delete [] buffer;
}

int Experiment2() {
  char *buffer, *buf;
  unsigned int offset;
  int StartWriteSize = INCREMENT*MB, StepWriteSize = INCREMENT*MB, EndWriteSize = ENDSIZE*MB, WriteSize,
    fd, j, k;
  struct timeval tvBefore, tvAfter;  //will hold the time difference
  bool alternate = true;

  currentExperiment = 2;
  printf("\nExperiment #%d\n", currentExperiment);
  printf("Sequential write to filesystem (buffer cache disabled and overwrite)\n");
  printf("Size in MB\t\t\tRate\n");

  //allocate buffer
  buffer = new char[CHUNK+SECTORSIZE];

  //align buffer
  offset = (unsigned int)buffer;

  if (offset % SECTORSIZE) { //not aligned
    buf = buffer + (SECTORSIZE - offset % SECTORSIZE);
  }    
  else {
    buf = buffer;
  }
  
  //loop incrementing the read size each time
  for (WriteSize = StartWriteSize; WriteSize <= EndWriteSize; WriteSize += StepWriteSize) {
    //open the disk file
    //reopening each time you write will always reset to the begining of the 
    //disk, so you don't have to lseek

    fd=open("/mnt/scsi_c/736Project/write_file", O_CREAT | O_WRONLY );
    if (fd < 0) {
      LogError(currentExperiment);
    }
    
    //start the timer
    if (gettimeofday(&tvBefore, NULL) == -1) {
      LogError(currentExperiment);
    }
    
    for(j=0; j< (WriteSize/CHUNK); j++) {
      //write the chunk of data
      k=write(fd, buf, CHUNK);
      if (k < 0) {
	LogError(currentExperiment);
      }
    }

    //stop the timer
    if (gettimeofday(&tvAfter, NULL) == -1) {
      LogError(currentExperiment);
    }
    
    
    PrintRate(tvBefore, tvAfter, WriteSize);
    fsync(fd); //note the fsync is after end of timing     
    close(fd);  //close the file
   //unlink("/mnt/scsi_c/736Project/write_file");  //delete the file  
  }
  
  printf("\nExperiment #%d ended Successfully\n", currentExperiment);
 
  //deallocate the buffer
  delete [] buffer;
}





int Experiment3() {
  char *buffer, *buf;
  unsigned int offset;
  int StartReadSize = INCREMENT*MB, StepReadSize = INCREMENT*MB, EndReadSize = ENDSIZE*MB, ReadSize,
    fd, j, k, cool;
  struct timeval tvBefore, tvAfter;  //will hold the time difference
  bool alternate = true;

  currentExperiment = 3;
  printf("\nExperiment #%d\n", currentExperiment);
  printf("Sequential read from filesystem with hot start(coolgraph)\n");
  printf("Size in MB\t\t\tRate\n");

  //allocate buffer
  buffer = new char[CHUNK+SECTORSIZE];

  //align buffer
  offset = (unsigned int)buffer;

  if (offset % SECTORSIZE) { //not aligned
    buf = buffer + (SECTORSIZE - offset % SECTORSIZE);
  }    
  else {
    buf = buffer;
  }
  
  //loop incrementing the read size each time
 
  for (ReadSize = StartReadSize; ReadSize <= EndReadSize; ReadSize += StepReadSize) {
    //open the disk file
    //reopening each time you read will always reset to the begining of the 
    //disk, so you don't have to lseek

    //alternate between openning two big files to diminish the effect of file caching
    //between successive reads.
    for(cool=0; cool<2; cool++){
   // if (alternate) {
     // alternate = false;
      fd=open("/mnt/scsi_b/736Project/1000MB", O_RDONLY);
    //}
    //else {
     // alternate = true;
      //fd=open("/mnt/scsi_b/736Project/1000MB1", O_RDONLY| O_SYNC);
    //}
    if (fd < 0) {
     
      LogError(currentExperiment);
    }

    //start the timer
    if (gettimeofday(&tvBefore, NULL) == -1) {
      LogError(currentExperiment);
    }
    
    for(j=0; j< (ReadSize/CHUNK); j++) {
      //read the chunk of data in memory
      k=read(fd, buf, CHUNK);
      if (k < 0) {

	LogError(currentExperiment);

      }
    }
    //stop the timer
    if (gettimeofday(&tvAfter, NULL) == -1) {
      LogError(currentExperiment);
    }


    PrintRate(tvBefore, tvAfter, ReadSize);

    close(fd);  //close the raw interface 
  }
  }	
  
  printf("\nExperiment #%d ended Successfully\n", currentExperiment);
 
  //deallocate the buffer
  delete [] buffer;
}

int Experiment4(){
  int i,j;
  struct timeval tvBefore, tvAfter, tvDiff;  //will hold the time difference
  float timeinseconds;
  
   currentExperiment = 3;
   printf("\nExperiment #%d\n", currentExperiment);
   printf("Sequential read from filesystem of 250 MB and tim esingle read(readahead)\n");
   printf("Read Number\t\t\tTime\n");

  char  buffer[1024*1024];
  //char buffer[512], *buf;
  int fd=open("/mnt/scsi_c/736Project/write_file",  O_RDONLY );


  if (fd==-1){
        printf(strerror(errno));
        //if (errno==ENOENT)
        //	printf("ENOENT");
  	return 0;
  }
  for(i=0; i<=250; i++) {
    //printf (" I am in");
  if (gettimeofday(&tvBefore, NULL) == -1) {
      printf(strerror(errno));
      exit(1);
    }

    j=read(fd,buffer, 1024*1024);
    if(j==-1){
    	printf(strerror(errno));
    	exit(1);
    }

    if (gettimeofday(&tvAfter, NULL) == -1) {
      printf(strerror(errno));
      exit(1);
    }
    tvDiff.tv_sec = tvAfter.tv_sec - tvBefore.tv_sec;
    tvDiff.tv_usec = tvDiff.tv_usec - tvDiff.tv_usec;
    if (tvDiff.tv_usec < 0) { //adjust for usecs
      tvDiff.tv_usec += 1000000;
      tvDiff.tv_sec--;
    }
      //output the results to the results file
    timeinseconds = tvDiff.tv_sec+(float)tvDiff.tv_sec/100000;
    //float rate = ((float)i)/ MB /timeinseconds;

    printf("%d \t\t  %f \n",i, timeinseconds);



  }
  close(fd);

 }




int main(){

  

  
   Experiment1();
   Experiment2();
   Experiment3();
   Experiment4();
 
}









