Created
May 12, 2017 08:25
-
-
Save mengcz13/e97e509dc0c614a0161df26bcdd64853 to your computer and use it in GitHub Desktop.
CLOOK, funtion: Disk.DoCLOOK(self, rList)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
from Tkinter import * | |
from types import * | |
import math, random, time, sys, os | |
from optparse import OptionParser | |
from decimal import * | |
MAXTRACKS = 1000 | |
# states that a request/disk go through | |
STATE_NULL = 0 | |
STATE_SEEK = 1 | |
STATE_ROTATE = 2 | |
STATE_XFER = 3 | |
STATE_DONE = 4 | |
# | |
# TODO | |
# XXX transfer time | |
# XXX satf | |
# XXX skew | |
# XXX scheduling window | |
# XXX sstf | |
# XXX specify requests vs. random requests in range | |
# XXX add new requests as old ones complete (starvation) | |
# XXX run in non-graphical mode | |
# XXX better graphical display (show key, long lists of requests, more timings on screen) | |
# XXX be able to do "pure" sequential | |
# XXX add more blocks around outer tracks (zoning) | |
# XXX simple flag to make scheduling window a fairness window (-F) | |
# new algs to scan and c-scan the disk? | |
# | |
class Disk: | |
def __init__(self, addr, addrDesc, lateAddr, lateAddrDesc, | |
policy, seekSpeed, rotateSpeed, skew, window, compute, | |
graphics, zoning, initArmTrack): | |
self.addr = addr | |
self.addrDesc = addrDesc | |
self.lateAddr = lateAddr | |
self.lateAddrDesc = lateAddrDesc | |
self.policy = policy | |
self.seekSpeed = Decimal(seekSpeed) | |
self.rotateSpeed = Decimal(rotateSpeed) | |
self.skew = skew | |
self.window = window | |
self.compute = compute | |
self.graphics = graphics | |
self.zoning = zoning | |
self.armTrack = initArmTrack | |
# figure out zones first, to figure out the max possible request | |
self.InitBlockLayout() | |
# figure out requests | |
random.seed(options.seed) | |
self.requests = self.MakeRequests(self.addr, self.addrDesc) | |
self.lateRequests = self.MakeRequests(self.lateAddr, self.lateAddrDesc) | |
# graphical startup | |
self.width = 500 | |
if self.graphics: | |
self.root = Tk() | |
tmpLen = len(self.requests) | |
if len(self.lateRequests) > 0: | |
tmpLen += len(self.lateRequests) | |
self.canvas = Canvas(self.root, width=410, height=460 + ((tmpLen / 20) * 20)) | |
self.canvas.pack() | |
# fairness stuff | |
if self.policy == 'BSATF' and self.window != -1: | |
self.fairWindow = self.window | |
else: | |
self.fairWindow = -1 | |
print 'REQUESTS', self.requests | |
print '' | |
# for late requests | |
self.lateCount = 0 | |
if len(self.lateRequests) > 0: | |
print 'LATE REQUESTS', self.lateRequests | |
print '' | |
if self.compute == False: | |
print '' | |
print 'For the requests above, compute the seek, rotate, and transfer times.' | |
print 'Use -c or the graphical mode (-G) to see the answers.' | |
print '' | |
# BINDINGS | |
if self.graphics: | |
self.root.bind('s', self.Start) | |
self.root.bind('p', self.Pause) | |
self.root.bind('q', self.Exit) | |
# TRACK INFO | |
self.tracks = {} | |
self.trackWidth = 40 | |
self.tracks[0] = 140 | |
self.tracks[1] = self.tracks[0] - self.trackWidth | |
self.tracks[2] = self.tracks[1] - self.trackWidth | |
if (self.seekSpeed > 1 and self.trackWidth % self.seekSpeed != 0): | |
print 'Seek speed (%d) must divide evenly into track width (%d)' % (self.seekSpeed, self.trackWidth) | |
sys.exit(1) | |
if self.seekSpeed < 1: | |
x = (self.trackWidth / self.seekSpeed) | |
y = int(float(self.trackWidth) / float(self.seekSpeed)) | |
if float(x) != float(y): | |
print 'Seek speed (%d) must divide evenly into track width (%d)' % (self.seekSpeed, self.trackWidth) | |
sys.exit(1) | |
# DISK SURFACE | |
self.cx = self.width/2.0 | |
self.cy = self.width/2.0 | |
if self.graphics: | |
self.canvas.create_rectangle(self.cx-175, 30, self.cx - 20, 80, fill='gray', outline='black') | |
self.platterSize = 320 | |
ps2 = self.platterSize / 2.0 | |
if self.graphics: | |
self.canvas.create_oval(self.cx-ps2, self.cy-ps2, self.cx+ps2, self.cy + ps2, fill='darkgray', outline='black') | |
for i in range(len(self.tracks)): | |
t = self.tracks[i] - (self.trackWidth / 2.0) | |
if self.graphics: | |
self.canvas.create_oval(self.cx - t, self.cy - t, self.cx + t, self.cy + t, fill='', outline='black', width=1.0) | |
# SPINDLE | |
self.spindleX = self.cx | |
self.spindleY = self.cy | |
if self.graphics: | |
self.spindleID = self.canvas.create_oval(self.spindleX-3, self.spindleY-3, self.spindleX+3, self.spindleY+3, fill='orange', outline='black') | |
# DISK ARM | |
self.armTrack = self.armTrack | |
self.armSpeedBase = float(seekSpeed) | |
self.armSpeed = float(seekSpeed) | |
distFromSpindle = self.tracks[self.armTrack] | |
self.armWidth = 20 | |
self.headWidth = 10 | |
self.armX = self.spindleX - (distFromSpindle * math.cos(math.radians(0))) | |
self.armX1 = self.armX - self.armWidth | |
self.armX2 = self.armX + self.armWidth | |
self.armY1 = 50.0 | |
self.armY2 = self.width / 2.0 | |
self.headX1 = self.armX - self.headWidth | |
self.headX2 = self.armX + self.headWidth | |
self.headY1 = (self.width/2.0) - self.headWidth | |
self.headY2 = (self.width/2.0) + self.headWidth | |
if self.graphics: | |
self.armID = self.canvas.create_rectangle(self.armX1, self.armY1, self.armX2, self.armY2, fill='gray', outline='black') | |
self.headID = self.canvas.create_rectangle(self.headX1, self.headY1, self.headX2, self.headY2, fill='gray', outline='black') | |
self.targetSize = 10.0 | |
if self.graphics: | |
sz = self.targetSize | |
self.targetID = self.canvas.create_oval(self.armX1-sz, self.armY1-sz, self.armX1+sz, self.armY1+sz, fill='orange', outline='') | |
# IO QUEUE | |
self.queueX = 20 | |
self.queueY = 450 | |
self.requestCount = 0 | |
self.requestQueue = [] | |
self.requestState = [] | |
self.queueBoxSize = 20 | |
self.queueBoxID = {} | |
self.queueTxtID = {} | |
# draw each box | |
for index in range(len(self.requests)): | |
self.AddQueueEntry(int(self.requests[index]), index) | |
if self.graphics: | |
self.canvas.create_text(self.queueX - 5, self.queueY - 20, anchor='w', text='Queue:') | |
# scheduling window | |
self.currWindow = self.window | |
# draw current limits of queue | |
if self.graphics: | |
self.windowID = -1 | |
self.DrawWindow() | |
# initial scheduling info | |
self.currentIndex = -1 | |
self.currentBlock = -1 | |
# initial state of disk (vs seeking, rotating, transferring) | |
self.state = STATE_NULL | |
# DRAW BLOCKS on the TRACKS | |
for bid in range(len(self.blockInfoList)): | |
(track, angle, name) = self.blockInfoList[bid] | |
if self.graphics: | |
distFromSpindle = self.tracks[track] | |
xc = self.spindleX + (distFromSpindle * math.cos(math.radians(angle))) | |
yc = self.spindleY + (distFromSpindle * math.sin(math.radians(angle))) | |
cid = self.canvas.create_text(xc, yc, text=name, anchor='center') | |
else: | |
cid = -1 | |
self.blockInfoList[bid] = (track, angle, name, cid) | |
# angle of rotation | |
self.angle = Decimal(0.0) | |
# TIME INFO | |
if self.graphics: | |
self.timeID = self.canvas.create_text(10, 10, text='Time: 0.00', anchor='w') | |
self.canvas.create_rectangle(95,0,200,18, fill='orange', outline='orange') | |
self.seekID = self.canvas.create_text(100, 10, text='Seek: 0.00', anchor='w') | |
self.canvas.create_rectangle(195,0,300,18, fill='lightblue', outline='lightblue') | |
self.rotID = self.canvas.create_text(200, 10, text='Rotate: 0.00', anchor='w') | |
self.canvas.create_rectangle(295,0,400,18, fill='green', outline='green') | |
self.xferID = self.canvas.create_text(300, 10, text='Transfer: 0.00', anchor='w') | |
self.canvas.create_text(320, 40, text='"s" to start', anchor='w') | |
self.canvas.create_text(320, 60, text='"p" to pause', anchor='w') | |
self.canvas.create_text(320, 80, text='"q" to quit', anchor='w') | |
self.timer = 0 | |
# STATS | |
self.seekTotal = 0.0 | |
self.rotTotal = 0.0 | |
self.xferTotal = 0.0 | |
# set up animation loop | |
if self.graphics: | |
self.doAnimate = True | |
else: | |
self.doAnimate = False | |
self.isDone = False | |
# call this to start simulation | |
def Go(self): | |
if options.graphics: | |
self.root.mainloop() | |
else: | |
self.GetNextIO() | |
while self.isDone == False: | |
self.Animate() | |
# crappy error message | |
def PrintAddrDescMessage(self, value): | |
print 'Bad address description (%s)' % value | |
print 'The address description must be a comma-separated list of length three, without spaces.' | |
print 'For example, "10,100,0" would indicate that 10 addresses should be generated, with' | |
print '100 as the maximum value, and 0 as the minumum. A max of -1 means just use the highest' | |
print 'possible value as the max address to generate.' | |
sys.exit(1) | |
# | |
# ZONES AND BLOCK LAYOUT | |
# | |
def InitBlockLayout(self): | |
self.blockInfoList = [] | |
self.blockToTrackMap = {} | |
self.blockToAngleMap = {} | |
self.tracksBeginEnd = {} | |
self.blockAngleOffset = [] | |
zones = self.zoning.split(',') | |
assert(len(zones) == 3) | |
for i in range(len(zones)): | |
self.blockAngleOffset.append(int(zones[i]) / 2) | |
track = 0 # outer track | |
angleOffset = 2 * self.blockAngleOffset[track] | |
for angle in range(0, 360, angleOffset): | |
block = angle / angleOffset | |
self.blockToTrackMap[block] = track | |
self.blockToAngleMap[block] = angle | |
self.blockInfoList.append((track, angle, block)) | |
self.tracksBeginEnd[track] = (0, block) | |
pblock = block + 1 | |
track = 1 # middle track | |
skew = self.skew | |
angleOffset = 2 * self.blockAngleOffset[track] | |
for angle in range(0, 360, angleOffset): | |
block = (angle / angleOffset) + pblock | |
self.blockToTrackMap[block] = track | |
self.blockToAngleMap[block] = angle + (angleOffset * skew) | |
self.blockInfoList.append((track, angle + (angleOffset * skew), block)) | |
self.tracksBeginEnd[track] = (pblock, block) | |
pblock = block + 1 | |
track = 2 # inner track | |
skew = 2 * self.skew | |
angleOffset = 2 * self.blockAngleOffset[track] | |
for angle in range(0, 360, angleOffset): | |
block = (angle / angleOffset) + pblock | |
self.blockToTrackMap[block] = track | |
self.blockToAngleMap[block] = angle + (angleOffset * skew) | |
self.blockInfoList.append((track, angle + (angleOffset * skew), block)) | |
self.tracksBeginEnd[track] = (pblock, block) | |
self.maxBlock = pblock | |
# print 'MAX BLOCK:', self.maxBlock | |
# adjust angle to starting position relative | |
for i in self.blockToAngleMap: | |
self.blockToAngleMap[i] = (self.blockToAngleMap[i] + 180) % 360 | |
# print 'btoa map', self.blockToAngleMap | |
# print 'btot map', self.blockToTrackMap | |
# print 'bao', self.blockAngleOffset | |
def MakeRequests(self, addr, addrDesc): | |
(numRequests, maxRequest, minRequest) = (0, 0, 0) | |
if addr == '-1': | |
# first extract values from descriptor | |
desc = addrDesc.split(',') | |
if len(desc) != 3: | |
self.PrintAddrDescMessage(addrDesc) | |
(numRequests, maxRequest, minRequest) = (int(desc[0]), int(desc[1]), int(desc[2])) | |
if maxRequest == -1: | |
maxRequest = self.maxBlock | |
# now make list | |
tmpList = [] | |
for i in range(numRequests): | |
tmpList.append(int(random.random() * maxRequest) + minRequest) | |
return tmpList | |
else: | |
return addr.split(',') | |
# | |
# BUTTONS | |
# | |
def Start(self, event): | |
self.GetNextIO() | |
self.doAnimate = True | |
self.Animate() | |
def Pause(self, event): | |
if self.doAnimate == False: | |
self.doAnimate = True | |
else: | |
self.doAnimate = False | |
def Exit(self, event): | |
sys.exit(0) | |
# | |
# CORE SIMULATION and ANIMATION | |
# | |
def UpdateTime(self): | |
if self.graphics: | |
self.canvas.itemconfig(self.timeID, text='Time: ' + str(self.timer)) | |
self.canvas.itemconfig(self.seekID, text='Seek: ' + str(self.seekTotal)) | |
self.canvas.itemconfig(self.rotID, text='Rotate: ' + str(self.rotTotal)) | |
self.canvas.itemconfig(self.xferID, text='Transfer: ' + str(self.xferTotal)) | |
def AddRequest(self, block): | |
self.AddQueueEntry(block, len(self.requestQueue)) | |
def QueueMap(self, index): | |
numPerRow = 400 / self.queueBoxSize | |
return (index % numPerRow, index / numPerRow) | |
def DrawWindow(self): | |
if self.window == -1: | |
return | |
(col, row) = self.QueueMap(self.currWindow) | |
if col == 0: | |
(col, row) = (20, row - 1) | |
if self.windowID != -1: | |
self.canvas.delete(self.windowID) | |
self.windowID = self.canvas.create_line(self.queueX + (col * 20) - 10, self.queueY - 13 + (row * 20), | |
self.queueX + (col * 20) - 10, self.queueY + 13 + (row * 20), width=2) | |
def AddQueueEntry(self, block, index): | |
self.requestQueue.append((block, index)) | |
self.requestState.append(STATE_NULL) | |
if self.graphics: | |
(col, row) = self.QueueMap(index) | |
sizeHalf = self.queueBoxSize / 2.0 | |
(cx, cy) = (self.queueX + (col * self.queueBoxSize), self.queueY + (row * self.queueBoxSize)) | |
self.queueBoxID[index] = self.canvas.create_rectangle(cx - sizeHalf, cy - sizeHalf, cx + sizeHalf, cy + sizeHalf, fill='white') | |
self.queueTxtID[index] = self.canvas.create_text(cx, cy, anchor='center', text=str(block)) | |
def SwitchColors(self, c): | |
if self.graphics: | |
self.canvas.itemconfig(self.queueBoxID[self.currentIndex], fill=c) | |
self.canvas.itemconfig(self.targetID, fill=c) | |
def SwitchState(self, newState): | |
self.state = newState | |
self.requestState[self.currentIndex] = newState | |
def RadiallyCloseTo(self, a1, a2): | |
if a1 > a2: | |
v = a1 - a2 | |
else: | |
v = a2 - a1 | |
if v < self.rotateSpeed: | |
return True | |
return False | |
def DoneWithTransfer(self): | |
angleOffset = self.blockAngleOffset[self.armTrack] | |
# if int(self.angle) == (self.blockToAngleMap[self.currentBlock] + angleOffset) % 360: | |
if self.RadiallyCloseTo(self.angle, Decimal((self.blockToAngleMap[self.currentBlock] + angleOffset) % 360)): | |
# print 'END TRANSFER', self.angle, self.timer | |
self.SwitchState(STATE_DONE) | |
self.requestCount += 1 | |
return True | |
return False | |
def DoneWithRotation(self): | |
angleOffset = self.blockAngleOffset[self.armTrack] | |
# XXX there is a weird bug in here | |
# print self.timer, 'ROTATE:: ', self.currentBlock, 'currangle: ', self.angle, ' - mapangle: ', self.blockToAngleMap[self.currentBlock] | |
# print ' angleOffset ', angleOffset | |
# print ' blockMap ', (self.blockToAngleMap[self.currentBlock] - angleOffset) % 360 | |
# print ' self.angle ', self.angle, int(self.angle) | |
# if int(self.angle) == (self.blockToAngleMap[self.currentBlock] - angleOffset) % 360: | |
if self.RadiallyCloseTo(self.angle, Decimal((self.blockToAngleMap[self.currentBlock] - angleOffset) % 360)): | |
self.SwitchState(STATE_XFER) | |
# print ' --> DONE WITH ROTATION!', self.timer | |
return True | |
return False | |
def PlanSeek(self, track): | |
self.seekBegin = self.timer | |
self.SwitchColors('orange') | |
self.SwitchState(STATE_SEEK) | |
if track == self.armTrack: | |
self.rotBegin = self.timer | |
self.SwitchColors('lightblue') | |
self.SwitchState(STATE_ROTATE) | |
return | |
self.armTarget = track | |
self.armTargetX1 = self.spindleX - self.tracks[track] - (self.trackWidth / 2.0) | |
if track >= self.armTrack: | |
self.armSpeed = self.armSpeedBase | |
else: | |
self.armSpeed = - self.armSpeedBase | |
def DoneWithSeek(self): | |
# move the disk arm | |
self.armX1 += self.armSpeed | |
self.armX2 += self.armSpeed | |
self.headX1 += self.armSpeed | |
self.headX2 += self.armSpeed | |
# update it on screen | |
if self.graphics: | |
self.canvas.coords(self.armID, self.armX1, self.armY1, self.armX2, self.armY2) | |
self.canvas.coords(self.headID, self.headX1, self.headY1, self.headX2, self.headY2) | |
# check if done | |
if (self.armSpeed > 0.0 and self.armX1 >= self.armTargetX1) or (self.armSpeed < 0.0 and self.armX1 <= self.armTargetX1): | |
self.armTrack = self.armTarget | |
return True | |
return False | |
def DoSATF(self, rList): | |
minBlock = -1 | |
minIndex = -1 | |
minEst = -1 | |
# print '**** DoSATF ****', rList | |
for (block, index) in rList: | |
if self.requestState[index] == STATE_DONE: | |
continue | |
track = self.blockToTrackMap[block] | |
angle = self.blockToAngleMap[block] | |
# print 'track', track, 'angle', angle | |
# estimate seek time | |
dist = int(math.fabs(self.armTrack - track)) | |
seekEst = Decimal(self.trackWidth / self.armSpeedBase) * dist | |
# estimate rotate time | |
angleOffset = self.blockAngleOffset[track] | |
angleAtArrival = (Decimal(self.angle) + (seekEst * self.rotateSpeed)) | |
while angleAtArrival > 360.0: | |
angleAtArrival -= 360.0 | |
rotDist = Decimal((angle - angleOffset) - angleAtArrival) | |
while rotDist > 360.0: | |
rotDist -= Decimal(360.0) | |
while rotDist < 0.0: | |
rotDist += Decimal(360.0) | |
rotEst = rotDist / self.rotateSpeed | |
# finally, transfer | |
xferEst = (Decimal(angleOffset) * Decimal(2.0)) / self.rotateSpeed | |
totalEst = seekEst + rotEst + xferEst | |
# should probably pick one on same track in case of a TIE | |
if minEst == -1 or totalEst < minEst: | |
minEst = totalEst | |
minBlock = block | |
minIndex = index | |
# END loop | |
# when done | |
self.totalEst = minEst | |
assert(minBlock != -1) | |
assert(minIndex != -1) | |
return (minBlock, minIndex) | |
# | |
# actually doesn't quite do SSTF | |
# just finds all the blocks on the nearest track | |
# (whatever that may be) and returns it as a list | |
# | |
def DoSSTF(self, rList): | |
minDist = MAXTRACKS | |
minBlock = -1 | |
trackList = [] # all the blocks on a track | |
for (block, index) in rList: | |
if self.requestState[index] == STATE_DONE: | |
continue | |
track = self.blockToTrackMap[block] | |
dist = int(math.fabs(self.armTrack - track)) | |
if dist < minDist: | |
trackList = [] | |
trackList.append((block, index)) | |
minDist = dist | |
elif dist == minDist: | |
trackList.append((block, index)) | |
assert(trackList != []) | |
return trackList | |
def DoCLOOK(self, rList): | |
# Max -> Min | |
minBlock = -1 | |
minIndex = -1 | |
minEst = -1 | |
outTrack = -1 | |
outBlock = -1 | |
outIndex = -1 | |
# print '**** DoSATF ****', rList | |
for (block, index) in rList: | |
if self.requestState[index] == STATE_DONE: | |
continue | |
track = self.blockToTrackMap[block] | |
# angle = self.blockToAngleMap[block] | |
# print 'track', track, 'angle', angle | |
# estimate seek time | |
dist = int(math.fabs(self.armTrack - track)) | |
seekEst = Decimal(self.trackWidth / self.armSpeedBase) * dist | |
# estimate rotate time | |
# angleOffset = self.blockAngleOffset[track] | |
# angleAtArrival = (Decimal(self.angle) + (seekEst * self.rotateSpeed)) | |
# while angleAtArrival > 360.0: | |
# angleAtArrival -= 360.0 | |
# rotDist = Decimal((angle - angleOffset) - angleAtArrival) | |
# while rotDist > 360.0: | |
# rotDist -= Decimal(360.0) | |
# while rotDist < 0.0: | |
# rotDist += Decimal(360.0) | |
# rotEst = rotDist / self.rotateSpeed | |
# finally, transfer | |
# xferEst = (Decimal(angleOffset) * Decimal(2.0)) / self.rotateSpeed | |
# totalEst = seekEst + rotEst + xferEst | |
totalEst = seekEst | |
if outTrack == -1 or track < outTrack: | |
outTrack, outBlock, outIndex = track, block, index | |
if track < self.armTrack: | |
continue | |
# should probably pick one on same track in case of a TIE | |
if minEst == -1 or totalEst < minEst: | |
minEst = totalEst | |
minBlock = block | |
minIndex = index | |
# END loop | |
# when done | |
self.totalEst = minEst | |
if minBlock == -1: | |
return (outBlock, outIndex) | |
else: | |
return (minBlock, minIndex) | |
def UpdateWindow(self): | |
if self.fairWindow == -1 and self.currWindow > 0 and self.currWindow < len(self.requestQueue): | |
self.currWindow += 1 | |
if self.graphics: | |
self.DrawWindow() | |
def GetWindow(self): | |
if self.currWindow <= -1: | |
return len(self.requestQueue) | |
else: | |
if self.fairWindow != -1: | |
if self.requestCount > 0 and (self.requestCount % self.fairWindow == 0): | |
self.currWindow = self.currWindow + self.fairWindow | |
if self.currWindow > len(self.requestQueue): | |
self.currWindow = len(self.requestQueue) | |
if self.graphics: | |
self.DrawWindow() | |
return self.currWindow | |
else: | |
return self.currWindow | |
def GetNextIO(self): | |
# check if done: if so, print stats and end animation | |
if self.requestCount == len(self.requestQueue): | |
self.UpdateTime() | |
self.PrintStats() | |
self.doAnimate = False | |
self.isDone = True | |
return | |
# do policy: should set currentBlock, | |
if self.policy == 'FIFO': | |
(self.currentBlock, self.currentIndex) = self.requestQueue[self.requestCount] | |
self.DoSATF(self.requestQueue[self.requestCount:self.requestCount+1]) | |
elif self.policy == 'SATF' or self.policy == 'BSATF': | |
(self.currentBlock, self.currentIndex) = self.DoSATF(self.requestQueue[0:self.GetWindow()]) | |
elif self.policy == 'SSTF': | |
# first, find all the blocks on a given track (given window constraints) | |
trackList = self.DoSSTF(self.requestQueue[0:self.GetWindow()]) | |
# then, do SATF on those blocks (otherwise, will not do them in obvious order) | |
(self.currentBlock, self.currentIndex) = self.DoSATF(trackList) | |
elif self.policy == 'CLOOK': | |
(self.currentBlock, self.currentIndex) = self.DoCLOOK(self.requestQueue[0:self.GetWindow()]) | |
else: | |
print 'policy (%s) not implemented' % self.policy | |
sys.exit(1) | |
# once best block is decided, go ahead and do the seek | |
self.PlanSeek(self.blockToTrackMap[self.currentBlock]) | |
# add another block? | |
if len(self.lateRequests) > 0 and self.lateCount < len(self.lateRequests): | |
self.AddRequest(self.lateRequests[self.lateCount]) | |
self.lateCount += 1 | |
def Animate(self): | |
if self.graphics == True and self.doAnimate == False: | |
self.root.after(20, self.Animate) | |
return | |
# timer | |
self.timer += 1 | |
self.UpdateTime() | |
# see which blocks are rotating on the disk | |
# print 'SELF ANGLE', self.angle | |
self.angle = Decimal(self.angle + self.rotateSpeed) | |
if self.angle >= 360.0: | |
self.angle = Decimal(0.0) | |
# move the blocks | |
if self.graphics: | |
for (track, angle, name, cid) in self.blockInfoList: | |
distFromSpindle = self.tracks[track] | |
na = angle - self.angle | |
xc = self.spindleX + (distFromSpindle * math.cos(math.radians(na))) | |
yc = self.spindleY + (distFromSpindle * math.sin(math.radians(na))) | |
if self.graphics: | |
self.canvas.coords(cid, xc, yc) | |
if self.currentBlock == name: | |
sz = self.targetSize | |
self.canvas.coords(self.targetID, xc-sz, yc-sz, xc+sz, yc+sz) | |
# move the arm OR wait for a rotational delay | |
if self.state == STATE_SEEK: | |
if self.DoneWithSeek(): | |
self.rotBegin = self.timer | |
self.SwitchState(STATE_ROTATE) | |
self.SwitchColors('lightblue') | |
if self.state == STATE_ROTATE: | |
# check for read (disk arm must be settled) | |
if self.DoneWithRotation(): | |
self.xferBegin = self.timer | |
self.SwitchState(STATE_XFER) | |
self.SwitchColors('green') | |
if self.state == STATE_XFER: | |
if self.DoneWithTransfer(): | |
self.DoRequestStats() | |
self.SwitchState(STATE_DONE) | |
self.SwitchColors('red') | |
self.UpdateWindow() | |
currentBlock = self.currentBlock | |
self.GetNextIO() | |
nextBlock = self.currentBlock | |
if self.blockToTrackMap[currentBlock] == self.blockToTrackMap[nextBlock]: | |
if (currentBlock == self.tracksBeginEnd[self.armTrack][1] and nextBlock == self.tracksBeginEnd[self.armTrack][0]) or (currentBlock + 1 == nextBlock): | |
# need a special case here: to handle when we stay in transfer mode | |
(self.rotBegin, self.seekBegin, self.xferBegin) = (self.timer, self.timer, self.timer) | |
self.SwitchState(STATE_XFER) | |
self.SwitchColors('green') | |
# make sure to keep the animation going! | |
if self.graphics: | |
self.root.after(20, self.Animate) | |
def DoRequestStats(self): | |
seekTime = self.rotBegin - self.seekBegin | |
rotTime = self.xferBegin - self.rotBegin | |
xferTime = self.timer - self.xferBegin | |
totalTime = self.timer - self.seekBegin | |
if self.compute == True: | |
print 'Block: %3d Seek:%3d Rotate:%3d Transfer:%3d Total:%4d' % (self.currentBlock, seekTime, rotTime, xferTime, totalTime) | |
# if int(totalTime) != int(self.totalEst): | |
# print 'INTERNAL ERROR: estimate was', self.totalEst, 'whereas actual time to access block was', totalTime | |
# print 'Please report this bug and as much information as possible so as to make it easy to recreate. Thanks!' | |
# update stats | |
self.seekTotal += seekTime | |
self.rotTotal += rotTime | |
self.xferTotal += xferTime | |
def PrintStats(self): | |
if self.compute == True: | |
print '\nTOTALS Seek:%3d Rotate:%3d Transfer:%3d Total:%4d\n' % (self.seekTotal, self.rotTotal, self.xferTotal, self.timer) | |
# END: class Disk | |
# | |
# MAIN SIMULATOR | |
# | |
parser = OptionParser() | |
parser.add_option('-s', '--seed', default='0', help='Random seed', action='store', type='int', dest='seed') | |
parser.add_option('-a', '--addr', default='-1', help='Request list (comma-separated) [-1 -> use addrDesc]', action='store', type='string', dest='addr') | |
parser.add_option('-A', '--addrDesc', default='5,-1,0', help='Num requests, max request (-1->all), min request', action='store', type='string', dest='addrDesc') | |
parser.add_option('-S', '--seekSpeed', default='1', help='Speed of seek', action='store', type='string', dest='seekSpeed') | |
parser.add_option('-R', '--rotSpeed', default='1', help='Speed of rotation', action='store', type='string', dest='rotateSpeed') | |
parser.add_option('-p', '--policy', default='FIFO', help='Scheduling policy (FIFO, SSTF, SATF, BSATF)', action='store', type='string', dest='policy') | |
parser.add_option('-w', '--schedWindow', default=-1, help='Size of scheduling window (-1 -> all)', action='store', type='int', dest='window') | |
parser.add_option('-o', '--skewOffset', default=0, help='Amount of skew (in blocks)', action='store', type='int', dest='skew') | |
parser.add_option('-z', '--zoning', default='30,30,30', help='Angles between blocks on outer,middle,inner tracks', action='store', type='string', dest='zoning') | |
parser.add_option('-G', '--graphics', default=False, help='Turn on graphics', action='store_true', dest='graphics') | |
parser.add_option('-l', '--lateAddr', default='-1', help='Late: request list (comma-separated) [-1 -> random]', action='store', type='string', dest='lateAddr') | |
parser.add_option('-L', '--lateAddrDesc', default='0,-1,0', help='Num requests, max request (-1->all), min request', action='store', type='string', dest='lateAddrDesc') | |
parser.add_option('-c', '--compute', default=False, help='Compute the answers', action='store_true', dest='compute') | |
parser.add_option('-i', '--initArmTrack', default=0, help='Set initial position of arm track', action='store', type='int', dest='initArmTrack') | |
(options, args) = parser.parse_args() | |
print 'OPTIONS seed', options.seed | |
print 'OPTIONS addr', options.addr | |
print 'OPTIONS addrDesc', options.addrDesc | |
print 'OPTIONS seekSpeed', options.seekSpeed | |
print 'OPTIONS rotateSpeed', options.rotateSpeed | |
print 'OPTIONS skew', options.skew | |
print 'OPTIONS window', options.window | |
print 'OPTIONS policy', options.policy | |
print 'OPTIONS compute', options.compute | |
print 'OPTIONS graphics', options.graphics | |
print 'OPTIONS zoning', options.zoning | |
print 'OPTIONS lateAddr', options.lateAddr | |
print 'OPTIONS lateAddrDesc', options.lateAddrDesc | |
print 'OPTIONS initArmTrack', options.initArmTrack | |
print '' | |
if options.window == 0: | |
print 'Scheduling window (%d) must be positive or -1 (which means a full window)' % options.window | |
sys.exit(1) | |
if options.graphics and options.compute == False: | |
print '\nWARNING: Setting compute flag to True, as graphics are on\n' | |
options.compute = True | |
# set up simulator info | |
d = Disk(addr=options.addr, addrDesc=options.addrDesc, lateAddr=options.lateAddr, lateAddrDesc=options.lateAddrDesc, | |
policy=options.policy, seekSpeed=Decimal(options.seekSpeed), rotateSpeed=Decimal(options.rotateSpeed), | |
skew=options.skew, window=options.window, compute=options.compute, graphics=options.graphics, zoning=options.zoning, | |
initArmTrack=options.initArmTrack) | |
# run simulation | |
d.Go() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment