//=================================================== file = diskdrive.c =====
//=  A CSIM simulation of a disk drive                                       =
//============================================================================
//=  Notes:
//=   1) This is a "first order" model of a disk drive. It does not model    =
//=      effects of sequential requests on head seek time or caching.        =
//=   2) Assume exponentially distributed file request interarrival times    =
//=      and exponentially distirbuted file sizes.                           =
//=--------------------------------------------------------------------------=
//=  Execution: diskdrive a1 a2 a3 a4 a5 a6 a7 a8                            =
//=              - a1 = Simulation time in hours                             =
//=              - a2 = Request_rate in files per second                     =
//=              - a3 = File_size mean file size in bytes                    =
//=              - a4 = Prob_hit probability of a cache hit                  =
//=              - a5 = Seek_time head seek time in seconds                  =
//=              - a6 = Spin_time disk spin time in seconds                  =
//=              - a7 = Read_rate1 cache read rate in bytes/sec              =
//=              - a8 = Read_rate2 disk read rate in bytes/sec               =
//=--------------------------------------------------------------------------=
//=  Build: Standard CSIM build                                              =
//=--------------------------------------------------------------------------=
//=  History: KJC (07/01/09) - Genesis                                       =
//============================================================================
//----- Includes --------------------------------------------------------------
#include <stdio.h>              // Needed for printf()
#include <stdlib.h>             // Needed for atol() and atof()
#include "csim.h"               // Needed for CSIM stuff

//----- Globals ---------------------------------------------------------------
FACILITY Disk_facility;         // Disk facility
TABLE    Resp_table;            // Response time table
double   Sim_time;              // Simulation time in hours
double   Request_rate;          // Request rate in files per second
double   File_size;             // Mean file size in bytes
double   Prob_hit;              // Probability of a cache hit
double   Seek_time;             // Head seek time in seconds
double   Spin_time;             // Disk spin time in seconds
double   Read_rate1;            // Cache read rate in bytes per second
double   Read_rate2;            // Disk read rate in bytes per second
int      Total_req;             // Counter for total number of requests
int      Cache_hit;             // Counter for number of cache hits

//----- Prototypes ------------------------------------------------------------
void gen(void);                               // Generate read requests
void disk(double file_size, double org_time); // Handle read requests

//=============================================================================
//==  Main program                                                           ==
//=============================================================================
void sim(int argc, char *argv[])
{
  // Check if enough arguments
  if (argc != 9)
  {
    printf("  Usage is: 'diskdrive a1 a2 a3 a4 a5 a6 a7 a8' where:        \n");
    printf("              - a1 = Simulation time in hours                 \n");
    printf("              - a2 = Request_rate in files per second         \n");
    printf("              - a3 = File_size mean file size in bytes        \n");
    printf("              - a4 = Prob_hit probability of a cache hit      \n");
    printf("              - a5 = Seek_time head seek time in seconds      \n");
    printf("              - a5 = Spin_time disk spin time in seconds      \n");
    printf("              - a7 = Read_rate1 cache read rate in bytes/sec  \n");
    printf("              - a8 = Read_rate2 disk read rate in bytes/sec   \n");
    exit(1);
  }

  // Intialize operational parameters from command line entries
  Sim_time = atof(argv[1]);
  Request_rate = atof(argv[2]);
  File_size = atof(argv[3]);
  Prob_hit = atof(argv[4]);
  Seek_time = atof(argv[5]);
  Spin_time = atof(argv[6]);
  Read_rate1 = atof(argv[7]);
  Read_rate2 = atof(argv[8]);

  // Create the simulation
  create("sim");

  // Initialize CSIM stuff
  Disk_facility = facility("Disk facility");
  Resp_table = table("Response time table");

  // Reset all global counters
  Total_req = Cache_hit = 0;

  // Output begin-of-simulation banner
  printf("*** BEGIN SIMULATION *** \n");

  // Initiate gen() and hold for Sim_time
  gen();
  hold(3600.0 * Sim_time);

  // Output results
  printf("============================================================= \n");
  printf("==        >>>>> CSIM disk drive simulation <<<<<           == \n");
  printf("============================================================= \n");
  printf("=  Simulation time      = %f hours      \n", Sim_time);
  printf("=  File request rate    = %f files/sec  \n", Request_rate);
  printf("=  Mean file size       = %f bytes      \n", File_size);
  printf("=  Prob cache hit       = %f            \n", Prob_hit);
  printf("=  Head seek time       = %f sec        \n", Seek_time);
  printf("=  Read rate (cache)    = %f bytes/sec  \n", Read_rate1);
  printf("=  Read rate (disk)     = %f bytes/sec  \n", Read_rate2);
  printf("============================================================= \n");
  printf("=  CPU time             = %6.3f sec     \n", cputime());
  printf("============================================================= \n");
  printf("=  Total requests       = %d     \n", Total_req);
  printf("=  Cache hits           = %f %%  \n",
    100.0 * Cache_hit / Total_req);
  printf("&  Mean response time   = %f sec \n", table_mean(Resp_table));
  printf("&  Utilization of disk  = %f %%  \n", 100.0 * util(Disk_facility));
  printf("============================================================= \n");

  // Output end-of-simulation banner
  printf("*** END SIMULATION *** \n");
}

//=============================================================================
//==  Process to generate read requests to disk                              ==
//=============================================================================
void gen(void)
{
  create("gen");

  // Loop to create file requests
  while(1)
  {
    // Delay for an exponentially distributed read request interarrival time
    hold(expntl(1.0 / Request_rate));

   // Generate a read request for an exponentially distributed file size
    disk(expntl(File_size), clock);
  }
}

//=============================================================================
//==  Process to process read requests                                       ==
//=============================================================================
void disk(double file_size, double org_time)
{
  create("disk");

  // Increment the total number of read requests
  Total_req++;

  // Process the file read request
  reserve(Disk_facility);
  if (uniform(0.0, 1.0) < Prob_hit)
  {
    Cache_hit++;                      // Increment the cache hit counter
    hold(file_size / Read_rate1);     // Read the file bytes from cache
  }
  else
  {
    hold(uniform(0.0, Seek_time));     // Move the head
    hold(uniform(0.0, Spin_time));     // Spin the disk to position
    hold(file_size / Read_rate2);      // Read the file bytes from disk
  }
  release(Disk_facility);

  // Record the response time
  record((clock - org_time), Resp_table);
}

