add lec23 io-device spoc homework
This commit is contained in:
		
							parent
							
								
									1aac451d11
								
							
						
					
					
						commit
						f6b6d6299a
					
				
							
								
								
									
										81
									
								
								related_info/lab8/disksim-homework.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								related_info/lab8/disksim-homework.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					# 磁盘访问 练习
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 磁盘抽象模型
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					一个磁盘反指针旋转,有3个磁道和一个磁头,每个磁道有12个扇区。
 | 
				
			||||||
 | 
					完成一个磁盘访问请求的时间包括:寻道时间(seek time)+旋转时间(rotational time)+传输时间(transfer time)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					执行如下
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					$ ./disksim.py -a 10 -G
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`-a 10`表示访问扇区10, `-G`表示显示图形动画。
 | 
				
			||||||
 | 
					可以看到磁头在外侧磁道的扇区6的中间位置, 扇区10与扇区6在一个磁道上。在图形界面上按`s`键,将启动模拟执行过程。并在执行结束后,按`q`键,则退出图形,并显示统计结果如下:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					REQUESTS ['10']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Block:  10  Seek:  0  Rotate:105  Transfer: 30  Total: 135
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TOTALS      Seek:  0  Rotate:105  Transfer: 30  Total: 135
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					表示寻道时间是0个时间单位,旋转时间是105个时间单位,传输时间是30个时间单位,总共的磁盘访问请求的时间是135.注意从扇区6到扇区9,旋转了90度,而为了进行传输,需要从扇区9~10的中间位置开始,从扇区10~11的中间位置结束。所以需要再旋转15度,即旋转了105度,而每旋转1度花费1个时间单位,所以旋转花费了105个时间单位。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果执行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					$ ./disksim.py -a 10,11 -G
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					表明发出了2个磁盘访问请求,可得到如下的结果
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					REQUESTS ['10', '11']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Block:  10  Seek:  0  Rotate:105  Transfer: 30  Total: 135
 | 
				
			||||||
 | 
					Block:  11  Seek:  0  Rotate:  0  Transfer: 30  Total:  30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TOTALS      Seek:  0  Rotate:105  Transfer: 60  Total: 165
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					由于访问完扇区10后,紧接着立刻访问扇区11,所以寻道和旋转时间都是0,总的访问时间是165.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果需要寻道,比如执行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					$ ./disksim.py -a 10,18 -G
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					REQUESTS ['10', '18’]
 | 
				
			||||||
 | 
					Sector:  10  Seek:  0  Rotate:105  Transfer: 30  Total: 135
 | 
				
			||||||
 | 
					Sector:  18  Seek: 40  Rotate:170  Transfer: 30  Total: 240
 | 
				
			||||||
 | 
					TOTALS      Seek: 40  Rotate:275  Transfer: 60  Total: 375
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					这里一个寻道的时间是40个时间单位。且假设采用FIFO(FCFS)磁盘调度算法。当访问完扇区10后,磁头需要寻道到中间磁道处(包括扇区18),扇区10对应的中间磁道的扇区是22号扇区,从扇区22扇区18需要旋转7个扇区的距离(23,12,13,14,15,16,17),花费210个时间单位,注意这里面包含了40个寻道的时间单位,所以,旋转所化时间为210-40=170个时间单位。这样,总体的访问时间为375
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					请回答如下问题:
 | 
				
			||||||
 | 
					问题 1:请执行 FIFO磁盘调度策略
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					./disksim.py  采用FIFO -a 0
 | 
				
			||||||
 | 
					./disksim.py   -a 6
 | 
				
			||||||
 | 
					./disksim.py   -a 30
 | 
				
			||||||
 | 
					./disksim.py   -a 7,30,8
 | 
				
			||||||
 | 
					./disksim.py   -a 10,11,12,13,24,1
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					请回答每个磁盘请求序列的IO访问时间
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					问题 2:请执行 SSTF磁盘调度策略
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					./disksim.py   -a 10,11,12,13,24,1
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					请回答每个磁盘请求序列的IO访问时间
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					问题 3:请执行 SCAN, C-SCAN磁盘调度策略
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					./disksim.py   -a 10,11,12,13,24,1
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					请回答每个磁盘请求序列的IO访问时间
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										719
									
								
								related_info/lab8/disksim-homework.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										719
									
								
								related_info/lab8/disksim-homework.py
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,719 @@
 | 
				
			|||||||
 | 
					#! /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):
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # 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     = 0
 | 
				
			||||||
 | 
					        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 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)
 | 
				
			||||||
 | 
					        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')
 | 
				
			||||||
 | 
					(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 ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# run simulation
 | 
				
			||||||
 | 
					d.Go()
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user