#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "rdtimer.h"

#include <unistd.h>
#include <rk/rk.h>
#include <rk/css.h>
#include <rk/rk_error.h>
#include <rk/posix_timers.h>
#include <rk/timespec.h>
#include <sys/mman.h>

cpu_tick_data_t         own_rk_cpu_ticks_per_second = 299946931;
static inline void
own_tick2usec(cpu_tick_t tick, cpu_tick_t us)
{
        cpu_tick_data_t msec = MICROSEC;
        /* *us = (((*tick)*msec)+(rk_cpu_ticks_per_second/2))/rk_cpu_ticks_per_second;*/
        *us = ((*tick)*msec)/own_rk_cpu_ticks_per_second;
}


static inline void own_tick2nanosecond(long tick, long *ns) {
  cpu_tick_data_t cpu_tick;
  cpu_tick_data_t us;

  cpu_tick = (cpu_tick_data_t) tick;
  own_tick2usec(&cpu_tick, &us);
  *ns = (us) *1000;
}

#define BUFFSIZE 1024 
#define KB 1024
static char line[BUFFSIZE * KB];
static unsigned long long int timevec[4*KB];
//static int timereq_sec[4*KB];
//static int timereq_nsec[4*KB];
//static int timedone_sec[4*KB];
//static int timedone_nsec[4*KB];
rk_resource_set_t rs;
css_disk_cpu_reserve_attr_data_t attr;
rk_reserve_param_data_t p;
int bf_access = 500; /* us */
int af_access = 500;/* us */
int size = 500; /* KB */
int period = 500; /* ms  */
int deadline = 500; /* ms */
struct timespec fnow;

void usage(char *command) {
  printf("%s [filename] [size of blocks (KB)] [blocks to read] [number of loops(0-until the end of the file)]<break_time (ms)>\n", command);
}

int main(int argc, char *argv[])
{
  char filename[128], outfilename[128];
  FILE *fp,*fo;
  int bytes, break_time,blocks,i,j,loop;
  unsigned long long int tick_start,tick_stop;
  //  struct timespec t_start,t_stop;
  struct timespec sleep_time;
  struct timespec remain_time;
  long t_ns;
  
  if (argc < 4) {
    usage(argv[0]);
    return -1;
  }
  strcpy(filename, argv[1]);
  bytes = atoi(argv[2]); 
  blocks = atoi(argv[3]);
  if (argc<5) loop = 0;
  else loop = atoi(argv[4]);

  if (argc<6) break_time = 0;
  else break_time = atoi(argv[5]);

  if (bytes * blocks > BUFFSIZE) {
    printf("buffer overflow, should specify less than %d KB \n", BUFFSIZE);
    return -1;
  }
#if 0
  if (mlockall(MCL_FUTURE)) {
    printf("memory lock error \n");
    exit(1);
  }
#endif 
  /* try to load everything */
  memset(line,0,BUFFSIZE*KB); 
  fp = fopen(filename, "r"); 
  if (!fp) {
    printf("file open error! \n");
    return -1;
  }
  printf("Input the output filename \n");

  scanf("%s", outfilename);
  fo = fopen(outfilename, "w");
  if (!fo) {
    printf("file output error! \n");
    return -1;
  }
  fprintf(fo,"#filename = %s bytes = %d blocks = %d  breaktime = %d ms\n",filename, bytes, blocks, break_time);
  fprintf(fo,"#Completion time in micro-seconds \n");
  fprintf(fo,"# <iteration> <completion time> \n");

  /* create resource set */
  rs = rk_resource_set_create("diskmeasureP");
  if (!rs) {
    printf("resource set create error ! \n");
  }
  /* create css reserve */
  p.enf_mode = RSV_HARD;		/* enum in rk.h   */ 
  p.sch_mode = RSV_HARD;
  p.rep_mode = RSV_HARD;

  attr.compute_bf.tv_sec = bf_access/1000000;
  attr.compute_bf.tv_nsec = (bf_access%1000000) * 1000;
  attr.compute_af.tv_sec = af_access/1000000;
  attr.compute_af.tv_nsec = (af_access%1000000) *  1000;
  attr.size = size *KB;
  attr.period.tv_sec = period/1000;
  attr.period.tv_nsec = (period%1000) * 1000000;
  attr.deadline = attr.period;
  
  printf("reserve is set for bf (%d,%d) af (%d,%d) %d KB in (%d,%d) w/ deadline (%d,%d) \n", 
	 (int)attr.compute_bf.tv_sec,
	 (int)attr.compute_bf.tv_nsec,
	 (int)attr.compute_af.tv_sec,
	 (int)attr.compute_af.tv_nsec,
	 (int)size,
	 (int)attr.period.tv_sec,
	 (int)attr.period.tv_nsec,
	 (int)attr.deadline.tv_sec,
	 (int)attr.deadline.tv_nsec);
  
  attr.blocking_time.tv_sec = (long int) 0;
  attr.blocking_time.tv_nsec = (long int) 0;
  clock_gettime(CLOCK_REALTIME, &fnow);
  // attr.start_time.tv_sec = (long int) 0;
  //attr.start_time.tv_nsec = (long int) 0; 
  attr.start_time.tv_sec = (long int) fnow.tv_sec+1;
  attr.start_time.tv_nsec = (long int) fnow.tv_nsec;
  attr.reserve_type = p;
  if (css_disk_cpu_reserve_create(rs, &attr)) {
    printf("css create failed!\n");
    rk_resource_set_destroy(rs);
    return 1;
  }

  /* Let's wait that the reserves are attached to their resource sets */
  while (rk_resource_set_get_cpu_rsv(rs) == 0);

  if (rk_resource_set_attach_process(rs, getpid())) {
    printf("attach process error!\n");
    rk_resource_set_destroy(rs);
    return 1;
  }
  if (loop == 0) loop = 4*KB;

  /* Synchronize with the reserve */
  fnow.tv_sec += 3;

  rt_make_periodic(&attr.period, &fnow);
  {
     int tmp;
     scanf("%d \n", &tmp);
  }
  rt_wait_for_start_time();

  for (i=0; i<loop;i++) {
    line[0]=0;
    tick_start = timer_read();
    //    clock_gettime(CLOCK_REALTIME, &t_start);
    if (!fread(line, bytes * KB, blocks, fp)) {
      goto close;
    }
    tick_stop = timer_read();
    //    clock_gettime(CLOCK_REALTIME, &t_stop);
    {
      /* find completion time */
      //unsigned long tm1, tm2;
      //tm1 = t_start.tv_sec * 1000000 + t_start.tv_nsec / 1000;
      //tm2 = t_stop.tv_sec * 1000000 + t_stop.tv_nsec / 1000;
      //printf("%d\n", i);
      //      timevec[i]=tm2-tm1;
      timevec[i]=tick_stop-tick_start;
      //      timereq_sec[i]=t_start.tv_sec;
      //      timereq_nsec[i]=t_start.tv_nsec;
      //      timedone_sec[i]=t_stop.tv_sec;
      //      timedone_nsec[i]=t_stop.tv_nsec;

    }
    if (break_time) {
      sleep_time.tv_sec = break_time/1000;
      sleep_time.tv_nsec = (break_time%1000)*1000000;
      nanosleep(&sleep_time, &remain_time);
    }
    rt_wait_for_next_period();
  }
 close:
  tick_stop = timer_read();
  //  clock_gettime(CLOCK_REALTIME, &t_stop);
  {
    /* find completion time */
    //    unsigned long tm1, tm2;
    // tm1 = t_start.tv_sec * 1000000 + t_start.tv_nsec / 1000;
    //    tm2 = t_stop.tv_sec * 1000000 + t_stop.tv_nsec / 1000;
    timevec[i]=0;
    //    timereq_sec[i]=0;             /* ignore all this */
    //    timereq_nsec[i]=0;
    //    timedone_sec[i]=0;
    //    timedone_nsec[i]=0;
  }
  /* destroy resource set */
  if (rk_resource_set_destroy(rs)) {
    printf("rk_resource_set_destory failed \n");
    return 1;
  }

  printf(" loop i ends at %d \n", i);
  if (i>=4*KB) printf("Warning: i beyonds the buffer size \n");
  fclose(fp); 

  if (own_rk_cpu_ticks_per_second) {
    fprintf(fo," #time (period) completion_time(msec) \n");
    for (j=0;i>0;i--,j++) {
      /* convert to nsec */
      own_tick2nanosecond(timevec[j], &t_ns);
      fprintf(fo,"%d %lu \n", j*period, (unsigned long) t_ns/1000000);
    }
  }
  else {
    fprintf(fo," #time (period) completion_time(ticks) \n");
    for (j=0;i>0;i--,j++) 
      fprintf(fo,"%d %lu\n",j*period,(unsigned long) timevec[j]);
  }
  fclose(fo);
  printf(".......end of the program write data output to %s complete!\n", outfilename);
#if 0
  if (munlockall()) {
   printf("unlock memory error \n");
   exit(1);
  }
#endif 

 
  return 0;
}  
