// C++/CSIM Disk Simulator #include #include #include "cpp.h" // class definitions #define OUTWARD 1 #define INWARD 2 #define MINSEEK 0.6 #define AVGSEEK 8 #define MAXSEEK 17 #define TRACKS_PER_DISK 3711 #define SECTORS_PER_TRACK 100 #define BYTES_PER_SECTOR 512 #define SECTORS_PER_REQUEST 1 #define BYTES_PER_REQUEST (BYTES_PER_SECTOR * SECTORS_PER_REQUEST) #define RPM 7200 #define NARS 10000 #define IAR_TM 10.0 event new_arrival("new_arrival"); event done("done"); table num_tracks_tbl("num of tracks"); table seek_time_tbl("seek time"); table rot_lat_tbl("rot lat"); table trans_time_tbl("transfer time"); table tbl("resp tms"); // table of response times float busy_time = 0.0f; float idle_time = 0.0f; float tot_time = 0.0f; int tot_bytes = 0; typedef struct { float arr_time; int track_num; int sector_num; } request; list disk_queue; // list of requests (disk queue) int curr_track = 1; float curr_sector = 1.0; int curr_direction = OUTWARD; void producer(); void consumer(); list::iterator fcfs_policy(); list::iterator scan_policy(); void print_queue(); float srv_time(list::iterator next); float get_seek_time(float x); float update_disk(float x); float get_transfer_time(); float get_rot_latency(float next, float curr); int closer(list::iterator x, list::iterator y); extern "C" void sim(int, char **); void sim(int argc, char *argv[]) { float first_clock; set_model_name("M/M/1 Queue"); create("sim"); first_clock = clock; producer(); consumer(); done.wait(); tot_time = clock - first_clock; printf("Busy time = %f\n", busy_time); printf("Idle time = %f\n", idle_time); printf("Total time = %f\n", tot_time); printf("Total bytes = %d\n", tot_bytes); printf("Throughput = %f\n", tot_bytes/busy_time); printf("Utilization = %f\n", 100.0f * busy_time/tot_time); report(); } // produces requests and places them in the list of requests void producer() { request new_req; create("producer"); for(int i = 1; i <= NARS; i++) { hold(expntl(IAR_TM)); // interarrival interval new_req.arr_time = clock; new_req.track_num = (int) ceil(uniform(0.0, TRACKS_PER_DISK)); new_req.sector_num = (int) ceil(uniform(0.0, SECTORS_PER_TRACK)); disk_queue.push_back(new_req); if (disk_queue.size() == 1) new_arrival.set(); // print_queue(); } } // processes requests in a policy-defined order from the list of requests void consumer() { list::iterator next; float old_time; create("consumer"); new_arrival.wait(); for(int i = 1; i <= NARS; i++) { if (disk_queue.empty()){ new_arrival.clear(); old_time = clock; new_arrival.wait(); update_disk(clock - old_time); idle_time += (clock - old_time); } next = scan_policy(); hold(srv_time(next)); tot_bytes += BYTES_PER_REQUEST; tbl.record(clock - next->arr_time); // record response time disk_queue.erase(next); // print_queue(); } done.set(); } float update_disk(float x) { curr_sector = curr_sector + x * RPM * SECTORS_PER_TRACK / 60000; while (curr_sector > SECTORS_PER_TRACK) curr_sector = curr_sector - SECTORS_PER_TRACK; } float get_seek_time(float x) { float a, b, c; if (x == 0.0) return x; a = (-10 * MINSEEK + 15 * AVGSEEK - 5 * MAXSEEK) / (3 * sqrt(TRACKS_PER_DISK)); b = (7 * MINSEEK - 15 * AVGSEEK + 8 * MAXSEEK) / (3 * TRACKS_PER_DISK); c = MINSEEK; return ( a * sqrt(x - 1.0) + b * (x - 1.0) + c ); } float get_rot_latency(float next, float curr) { float x; if (next >= curr) x = next - curr; else x = next + SECTORS_PER_TRACK - curr; return ( x * 60000/ (RPM * SECTORS_PER_TRACK) ); } float get_transfer_time() { return (((float) BYTES_PER_REQUEST * 60000) / (BYTES_PER_SECTOR * SECTORS_PER_TRACK * RPM)); } float srv_time(list::iterator next) { float seek_time, rot_latency, transfer_time; num_tracks_tbl.record(fabs(next->track_num - curr_track)); seek_time = get_seek_time(fabs(next->track_num - curr_track)); seek_time_tbl.record(seek_time); curr_track = next->track_num; rot_latency = get_rot_latency(next->sector_num, curr_sector); rot_lat_tbl.record(rot_latency); curr_sector = next->sector_num; transfer_time = get_transfer_time(); trans_time_tbl.record(transfer_time); curr_sector = curr_sector + SECTORS_PER_REQUEST; if (curr_sector > SECTORS_PER_TRACK) curr_sector = curr_sector - SECTORS_PER_TRACK; busy_time += seek_time + rot_latency + transfer_time; return seek_time + rot_latency + transfer_time; } // gets the next request from the list of requests according to the policy // in this case : fcfs list::iterator fcfs_policy() { list::iterator earliest; earliest = disk_queue.begin(); for (list::iterator i = disk_queue.begin(); i != disk_queue.end(); ++i) { if (i->arr_time < earliest->arr_time) earliest = i; } return earliest; } // gets the next request from the list of requests according to the policy // in this case : scan list::iterator scan_policy() { list::iterator closest; closest = disk_queue.begin(); for (list::iterator i = disk_queue.begin(); i != disk_queue.end(); ++i) { if (closer(i, closest)){ /* fprintf(stderr, "**** %d is closer than %d when curr is %d and dir is %s\n", i->track_num, closest->track_num, curr_track, (curr_direction == 1) ? "outward":"inward"); */ closest = i; } } curr_direction = (closest->track_num < curr_track) ? INWARD : OUTWARD ; return closest; } /* Approximation: Not using rotational latency at all, just seek for scan algorithm */ int closer(list::iterator x, list::iterator y) { if (curr_direction == OUTWARD) { if (x->track_num < y->track_num) { if (curr_track <= x->track_num) return 1; else return 0; } else if (x->track_num > y->track_num) { if (curr_track <= y->track_num) return 0; else return 1; } else { return 1; } } else { if (x->track_num < y->track_num) { if (curr_track >= y->track_num) return 0; else return 1; } else if (x->track_num > y->track_num) { if (curr_track >= x->track_num) return 1; else return 0; } else { return 0; } } } // print queue for debugging purposes. Note use this only with a small // NARS value void print_queue() { fprintf(stderr, "[%f] ", clock); for (list::iterator i = disk_queue.begin(); i != disk_queue.end(); ++i) { fprintf(stderr, "<%f, %d, %d> ", i->arr_time, i->track_num, i->sector_num); } fprintf(stderr, "\n"); }