///////////////////////////////////////////
// stat.c  -- statistics for NASD simulator
////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
#include <strings.h>

#include "iotrace.h"
#include "Manager.h"
#include "NASD.h"
#include "stat.h"

NasdStat::NasdStat(int blocksize, int columnnum)
{
  Access = new AccessStr[columnnum + 1];
  
  for (int i = 0; i <= columnnum; i++) {
    //    Access[i].TotalAccessTime = 0;
    Access[i].TotalMTime = 0;
    Access[i].TotalNTime = 0;
    Access[i].TotalDTime = 0;
    Access[i].OpNum = 0;
  }
    

  TotalOpNum = 0;

  BlockSize = blocksize;
  ColumnNum = columnnum;

  AllOpTime = 0;
  AllOpNum = 0;

  WRNum = 0;

  //  TotalBlocks = 0;
  NetCount = 0;
}

NasdStat::~NasdStat()
{

  delete []Access;

}

void NasdStat::AddRequest(short op, unsigned bcount, TimeBD &Atime, unsigned netcount)
{

  if ((op == MYTRACE_READ) || (op == MYTRACE_WRITE)) {

    //if (Psize >= BlockSize * ColumnNum) {
    if (bcount > ColumnNum) {
      
      //Access[ColumnNum].TotalAccessTime += Atime/1000.0;
      Access[ColumnNum].TotalMTime += Atime.memtime/1000.0;
      Access[ColumnNum].TotalNTime += Atime.nettime/1000.0;
      Access[ColumnNum].TotalDTime += Atime.disktime/1000.0;
      Access[ColumnNum].OpNum++;
      Access[ColumnNum].TotalBlock += bcount;
    }

    else {

      Access[bcount - 1].TotalMTime += Atime.memtime/1000.0;
      Access[bcount - 1].TotalNTime += Atime.nettime/1000.0;
      Access[bcount - 1].TotalDTime += Atime.disktime/1000.0;
      //Access[Psize / BlockSize].TotalAccessTime += Atime/1000.0;
      Access[bcount - 1].OpNum++;
      Access[bcount - 1].TotalBlock += bcount;
    }
    
    //TotalBlocks += bcount;
    WRNum++;
  }

  AllOpTime += (Atime.memtime + Atime.nettime + Atime.disktime) / 1000.0;
  AllOpNum++;

  NetCount += netcount;
}

void NasdStat::PrintResult()
{
  double totalrwtime;
  double totalmemtime;
  double totaldisktime;
  double totalnettime;
  unsigned totalblocks;

  printf("Total Op Time: %lf ms    Total Op Num: %d    Avg Op Time:%lf ms\n\n", 
	 AllOpTime, AllOpNum, AllOpTime / AllOpNum);

  totalmemtime = 0;
  totaldisktime = 0;
  totalnettime = 0;
  totalblocks = 0;

  for (int i = 0; i < ColumnNum; i++) 
    {

      //totalrwtime += Access[i].TotalMTime + Access[i].TotalNTime + Access[i].TotalDTime;
      totalmemtime += Access[i].TotalMTime;
      totalnettime += Access[i].TotalNTime;
      totaldisktime += Access[i].TotalDTime;
      totalblocks += Access[i].TotalBlock;

      if (Access[i].OpNum != 0)
	{
	  totalrwtime = Access[i].TotalMTime + Access[i].TotalNTime + Access[i].TotalDTime;
	  
	  printf("Access size: %d BLKs   TotalNum R/W: %d    Average Time: %lf ms\n", 
		 i + 1,
		 Access[i].OpNum, totalrwtime / Access[i].OpNum);
	  printf("     Time Breakdown--- Disk:%lf ms, %lf%%\n", 
		 Access[i].TotalDTime / Access[i].OpNum, 
		 Access[i].TotalDTime * 100/ totalrwtime);
	  printf("                   --- Network:%lf ms, %lf%%\n", 
		 Access[i].TotalNTime / Access[i].OpNum, 
		 Access[i].TotalNTime * 100/ totalrwtime);
	  printf("                   --- Memory:%lf ms, %lf%%\n", 
		 Access[i].TotalMTime / Access[i].OpNum, 
		 Access[i].TotalMTime * 100/ totalrwtime);

	  printf("     Average access time per block: %lf ms\n", 
		 totalrwtime / Access[i].TotalBlock);
	  printf("     Time Breakdown--- Disk:%lf ms, %lf%%\n", 
		 Access[i].TotalDTime / Access[i].TotalBlock, 
		 Access[i].TotalDTime * 100/ totalrwtime);
	  printf("                   --- Network:%lf ms, %lf%%\n", 
		 Access[i].TotalNTime / Access[i].TotalBlock, 
		 Access[i].TotalNTime * 100/ totalrwtime);
	  printf("                   --- Memory:%lf ms, %lf%%\n", 
		 Access[i].TotalMTime / Access[i].TotalBlock, 
		 Access[i].TotalMTime * 100/ totalrwtime);
	}
    } // end of for

  if (Access[ColumnNum].OpNum != 0)
    {
      totalrwtime = Access[ColumnNum].TotalMTime + Access[ColumnNum].TotalNTime 
	+ Access[ColumnNum].TotalDTime;
      
      printf("Access size: >%d BLKs   TotalNum R/W: %d    Average Time: %lf ms\n", 
	     ColumnNum, //ColumnNum * BlockSize,
	     Access[ColumnNum].OpNum,
	     totalrwtime / Access[ColumnNum].OpNum);
      printf("     Time Breakdown--- Disk:%lf ms, %lf%%\n", 
	     Access[ColumnNum].TotalDTime / Access[ColumnNum].OpNum, 
	     Access[ColumnNum].TotalDTime * 100/ totalrwtime);
      printf("                   --- Network:%lf ms, %lf%%\n", 
	     Access[ColumnNum].TotalNTime / Access[ColumnNum].OpNum, 
	     Access[ColumnNum].TotalNTime * 100/ totalrwtime);
      printf("                   --- Memory:%lf ms, %lf%%\n", 
	     Access[ColumnNum].TotalMTime / Access[ColumnNum].OpNum, 
	     Access[ColumnNum].TotalMTime * 100/ totalrwtime);

      printf("     Average access time per block: %lf ms\n", 
	     totalrwtime / Access[ColumnNum].TotalBlock);
      printf("     Time Breakdown--- Disk:%lf ms, %lf%%\n", 
	     Access[ColumnNum].TotalDTime / Access[ColumnNum].TotalBlock, 
	     Access[ColumnNum].TotalDTime * 100/ totalrwtime);
      printf("                   --- Network:%lf ms, %lf%%\n", 
	     Access[ColumnNum].TotalNTime / Access[ColumnNum].TotalBlock, 
	     Access[ColumnNum].TotalNTime * 100/ totalrwtime);
      printf("                   --- Memory:%lf ms, %lf%%\n", 
	     Access[ColumnNum].TotalMTime / Access[ColumnNum].TotalBlock, 
	     Access[ColumnNum].TotalMTime * 100/ totalrwtime);
    }

  //totalrwtime += Access[ColumnNum].TotalAccessTime;
  totalmemtime += Access[ColumnNum].TotalMTime;
  totalnettime += Access[ColumnNum].TotalNTime;
  totaldisktime += Access[ColumnNum].TotalDTime;

  totalrwtime = totalmemtime + totalnettime + totaldisktime;

  printf("\nTotal number of Read/Writes: %d\n", WRNum);
  printf("Average time per Read/Write: %lf ms\n", totalrwtime / WRNum);
  printf("     Time Breakdown--- Disk:%lf ms, %lf%%\n",
	 totaldisktime / WRNum, totaldisktime * 100/ totalrwtime);
  printf("                   --- Network:%lf ms, %lf%%\n",
	 totalnettime / WRNum, totalnettime * 100/ totalrwtime);
  printf("                   --- Memory:%lf ms, %lf%%\n",
	 totalmemtime / WRNum, totalmemtime * 100/ totalrwtime);

  printf("Average access time per block: %lf ms\n", totalrwtime / totalblocks);
  printf("     Time Breakdown--- Disk:%lf ms, %lf%%\n",
	 totaldisktime / totalblocks, totaldisktime * 100/ totalrwtime);
  printf("                   --- Network:%lf ms, %lf%%\n",
	 totalnettime / totalblocks, totalnettime * 100/ totalrwtime);
  printf("                   --- Memory:%lf ms, %lf%%\n",
	 totalmemtime / totalblocks, totalmemtime * 100/ totalrwtime);

  // printf("The Average Bandwidth of Read/Write: %lf KB/s\n", TotalBytes / totalrwtime);
  printf("\nTotal network communications: %d\n", NetCount);
  printf("Average communciations # per Read/Write: %lf\n", NetCount * 1.0 / WRNum);
  printf("Average communciations # per block: %lf\n", NetCount * 1.0 / totalblocks);
}
