LRU之前做过,OPT 最佳淘汰算法是一种理想状态的算法,是去寻找后面没有使用,或者最晚使用的那个cache中的页面淘汰掉。
急着回去睡觉,不废话了。
代码实现
#-*-coding:utf-8-*-
from numpy import *
#一行四个输出
def MyPrint(lst,strlst):
i=0
for j in range(len(lst)):
print strlst,'[',j,']=',lst[j],
i+=1
if i%4==0:
print
#生成并输出地址表
def VtrAds():
a=[-1 for i in range(256)] #存虚拟地址的数组
#放入顺序增长的地址,每次4个
index=0
for i in range(32):
index+=random.randint(0,4) #随机地加一点
RandAds=random.randint(12767,22767) #随机生成一个起始地址
#写入连续地址
a[index]=RandAds
a[index+1]=RandAds+1
a[index+2]=RandAds+2
a[index+3]=RandAds+3
index+=4 #跳跃到下一个位置
#放入较小的地址
index=0
skip=False #决定要不要跳过(交叉放入)
lftCount=0
while(True):
#如果放入的数目足够了就结束循环
if lftCount>=64:
break
#如果能放并且不用跳过
if a[index]<0 and skip==False:
a[index]=random.randint(0,12766) #放入一个小地址
lftCount+=1 #记录成功放入了一次
skip=True #下次就需要跳过了
#如果能放入但需要跳过
elif a[index]<0 and skip==True:
skip=False #下次就不用跳过了
index+=1 #指向下一个需要选择的地址
#放入较大的地址
for index in range(256):
#只要是空的
if a[index]<0:
a[index]=random.randint(22768,32767) #就直接放入
a=array(a) #转换为numpy数组
#a=reshape(a,(-1,4)) #每行4个
#按行输出
print 'THE VIRTUAL ADDRESS STREAM AS FOLLOWS:'
MyPrint(a,'a')
print '='*30
return a
#OPT算法
def MyOpt(i,a):
print '-'*30
print 'PAGE NUMBER WITH SIZE %dk FOR EACH ADDRESS IS:'%i
yita=i*1024 #表示页面大小
pageno=[num/yita+1 for num in a]
'''
pageno=a/yita
#变成int
for j in range(len(pageno)):
pageno[j]=int(pageno[j])
'''
MyPrint(pageno,'pageno')
print 'page assigned',' '*20,'page_in/total reference'
for lnth in range(4,34,2):
ok=getInOpt(lnth,pageno)
print lnth,' '*40,ok
'''
#判断元素是否在列表里
def isIn(a,lst):
for b in lst:
if a==b:
return True
return False
'''
#获取OPT命中率
def getInOpt(lnth,pageno):
cache=[]
innum=0
#对于需要的每个页面
for i in range(len(pageno)):
'''
if len(cache)==0: #小心越界,单独判断
cache.append(pageno[i]) #把页面加入进来
continue
'''
#如果已经在cache里面
if pageno[i] in cache:
innum+=1
continue #直接使用就行了,进入下一次
#如果不在,但cache未满
elif len(cache)<lnth:
cache.append(pageno[i]) #把页面加入进来
else: #OPT的核心(如果cache满时缺页)
cache=lossOpt(cache,pageno,i) #更新cache
return float(innum)/len(pageno)
#用于在Opt算法下更新cache
def lossOpt(cache,pageno,i):
#bye数组记录哪个页不要了
bye=[False for j in range(len(cache))]
num=0 #记录已经有几个要留下
#循环去看后面的每个页pageno[j]
for j in range(i+1,len(pageno)):
if num==len(cache)-1: #如果已经找到这么多
break
#如果有新的缺页项
if (pageno[j] in cache)\
and (bye[cache.index(pageno[j])]==False):
num+=1 #新的缺页项
bye[cache.index(pageno[j])]=True
#拿掉那个还是False的
#即使后面的元素不够多,在循环体外拿掉也是正确的
for k in range(len(bye)):
if bye[k]==False:
del cache[k]
break #拿掉一个就退出!
return cache #返回新的cache
#获取LRU命中率
def getInLru(lnth,pageno):
cache=[]
innum=0 #命中次数
for i in range(len(pageno)): #每个页面号i
if pageno[i] not in cache: #如果不在cache中,即缺页
if len(cache)<lnth: #如果cache未满
#就在其尾部添加这一页(新加的在后面)
cache.append(pageno[i])
else: #如果cache满了
#拿掉最不常用的(在最前)
#即把后面的前移
cache[0:lnth-1:]=cache[1:lnth:]
cache[lnth-1::]=[pageno[i]] #将这页放在最后
else: #如果在cache中,即命中,注意这时不能用lnth了
innum+=1 #记录
#这时候要把那个页放到最后面,不改变其它的相对顺序
#将它之后的页都复制到从它向后的位置
#并在最后留一个空位保证不改变cache长度
#所以保守地显示指明len(cache)-1
cache[cache.index(pageno[i]):len(cache)-1:]=\
cache[cache.index(pageno[i])+1::]
#把这一页放在最后(最新)
cache[len(cache)-1::]=[pageno[i]]
return float(innum)/len(pageno)
#LRU算法
def MyLru(i,a):
print '-'*30
print 'PAGE NUMBER WITH SIZE %dk FOR EACH ADDRESS IS:'%i
yita=i*1024 #表示页面大小
pageno=[num/yita+1 for num in a]
MyPrint(pageno,'pageno')
print 'page assigned',' '*20,'page_in/total reference'
for lnth in range(4,34,2):
ok=getInLru(lnth,pageno)
print lnth,' '*40,ok
#便利函数作入口
def Go():
a=VtrAds() #生成地址表a
print '输入OPT/LRU选择算法:'
name=raw_input() #输入算法名称
if name!='OPT' and name!='LRU':
print '错误的输入,再见!'
return
print 'The algorithm is:',name
#执行算法
if name=='OPT':
for i in (1,2,4,8):
MyOpt(i,a)
elif name=='LRU':
for i in (1,2,4,8):
MyLru(i,a)
测试
随机地址表,按照要求一半是顺序执行,一半均匀散布在低地址,一半均匀散步在高地址。
页面大小取1k,2k,4k,8k,然后对每个页面大小,取cache能存的页数从4~32(步长2),测试一下快表命中率。
cache能存的页面数一样时,页面越大,命中率越大,因为一个页面能包容的地址更多了。
页面大小一样时,cache能存的页面数越多,命中率越大,因为cache里存的页面多了,自然更容易命中了。