os_kernel_lab/related_info/ostep/ostep6-paging-policy.py
2015-03-15 16:54:19 +08:00

276 lines
10 KiB
Python
Executable File

#! /usr/bin/env python
import sys
from optparse import OptionParser
import random
import math
def convert(size):
length = len(size)
lastchar = size[length-1]
if (lastchar == 'k') or (lastchar == 'K'):
m = 1024
nsize = int(size[0:length-1]) * m
elif (lastchar == 'm') or (lastchar == 'M'):
m = 1024*1024
nsize = int(size[0:length-1]) * m
elif (lastchar == 'g') or (lastchar == 'G'):
m = 1024*1024*1024
nsize = int(size[0:length-1]) * m
else:
nsize = int(size)
return nsize
def hfunc(index):
if index == -1:
return 'MISS'
else:
return 'HIT '
def vfunc(victim):
if victim == -1:
return '-'
else:
return str(victim)
#
# main program
#
parser = OptionParser()
parser.add_option('-a', '--addresses', default='-1', help='a set of comma-separated pages to access; -1 means randomly generate', action='store', type='string', dest='addresses')
parser.add_option('-f', '--addressfile', default='', help='a file with a bunch of addresses in it', action='store', type='string', dest='addressfile')
parser.add_option('-n', '--numaddrs', default='10', help='if -a (--addresses) is -1, this is the number of addrs to generate', action='store', type='string', dest='numaddrs')
parser.add_option('-p', '--policy', default='FIFO', help='replacement policy: FIFO, LRU, OPT, UNOPT, RAND, CLOCK', action='store', type='string', dest='policy')
parser.add_option('-b', '--clockbits', default=2, help='for CLOCK policy, how many clock bits to use', action='store', type='int', dest='clockbits')
parser.add_option('-C', '--cachesize', default='3', help='size of the page cache, in pages', action='store', type='string', dest='cachesize')
parser.add_option('-m', '--maxpage', default='10', help='if randomly generating page accesses, this is the max page number', action='store', type='string', dest='maxpage')
parser.add_option('-s', '--seed', default='0', help='random number seed', action='store', type='string', dest='seed')
parser.add_option('-N', '--notrace', default=False, help='do not print out a detailed trace', action='store_true', dest='notrace')
parser.add_option('-c', '--compute', default=False, help='compute answers for me', action='store_true', dest='solve')
(options, args) = parser.parse_args()
print 'ARG addresses', options.addresses
print 'ARG addressfile', options.addressfile
print 'ARG numaddrs', options.numaddrs
print 'ARG policy', options.policy
print 'ARG clockbits', options.clockbits
print 'ARG cachesize', options.cachesize
print 'ARG maxpage', options.maxpage
print 'ARG seed', options.seed
print 'ARG notrace', options.notrace
print ''
addresses = str(options.addresses)
addressFile = str(options.addressfile)
numaddrs = int(options.numaddrs)
cachesize = int(options.cachesize)
seed = int(options.seed)
maxpage = int(options.maxpage)
policy = str(options.policy)
notrace = options.notrace
clockbits = int(options.clockbits)
random.seed(seed)
addrList = []
if addressFile != '':
fd = open(addressFile)
for line in fd:
addrList.append(int(line))
fd.close()
else:
if addresses == '-1':
# need to generate addresses
for i in range(0,numaddrs):
n = int(maxpage * random.random())
addrList.append(n)
else:
addrList = addresses.split(',')
if options.solve == False:
print 'Assuming a replacement policy of %s, and a cache of size %d pages,' % (policy, cachesize)
print 'figure out whether each of the following page references hit or miss'
print 'in the page cache.\n'
for n in addrList:
print 'Access: %d Hit/Miss? State of Memory?' % int(n)
print ''
else:
if notrace == False:
print 'Solving...\n'
# init memory structure
count = 0
memory = []
hits = 0
miss = 0
if policy == 'FIFO':
leftStr = 'FirstIn'
riteStr = 'Lastin '
elif policy == 'LRU':
leftStr = 'LRU'
riteStr = 'MRU'
elif policy == 'MRU':
leftStr = 'LRU'
riteStr = 'MRU'
elif policy == 'OPT' or policy == 'RAND' or policy == 'UNOPT' or policy == 'CLOCK':
leftStr = 'Left '
riteStr = 'Right'
else:
print 'Policy %s is not yet implemented' % policy
exit(1)
# track reference bits for clock
ref = {}
cdebug = False
# need to generate addresses
addrIndex = 0
for nStr in addrList:
# first, lookup
n = int(nStr)
try:
idx = memory.index(n)
hits = hits + 1
if policy == 'LRU' or policy == 'MRU':
update = memory.remove(n)
memory.append(n) # puts it on MRU side
except:
idx = -1
miss = miss + 1
victim = -1
if idx == -1:
# miss, replace?
# print 'BUG count, cachesize:', count, cachesize
if count == cachesize:
# must replace
if policy == 'FIFO' or policy == 'LRU':
victim = memory.pop(0)
elif policy == 'MRU':
victim = memory.pop(count-1)
elif policy == 'RAND':
victim = memory.pop(int(random.random() * count))
elif policy == 'CLOCK':
if cdebug:
print 'REFERENCE TO PAGE', n
print 'MEMORY ', memory
print 'REF (b)', ref
# hack: for now, do random
# victim = memory.pop(int(random.random() * count))
victim = -1
while victim == -1:
page = memory[int(random.random() * count)]
if cdebug:
print ' scan page:', page, ref[page]
if ref[page] >= 1:
ref[page] -= 1
else:
# this is our victim
victim = page
memory.remove(page)
break
# remove old page's ref count
if page in memory:
assert('BROKEN')
del ref[victim]
if cdebug:
print 'VICTIM', page
print 'LEN', len(memory)
print 'MEM', memory
print 'REF (a)', ref
elif policy == 'OPT':
maxReplace = -1
replaceIdx = -1
replacePage = -1
# print 'OPT: access %d, memory %s' % (n, memory)
# print 'OPT: replace from FUTURE (%s)' % addrList[addrIndex+1:]
for pageIndex in range(0,count):
page = memory[pageIndex]
# now, have page 'page' at index 'pageIndex' in memory
whenReferenced = len(addrList)
# whenReferenced tells us when, in the future, this was referenced
for futureIdx in range(addrIndex+1,len(addrList)):
futurePage = int(addrList[futureIdx])
if page == futurePage:
whenReferenced = futureIdx
break
# print 'OPT: page %d is referenced at %d' % (page, whenReferenced)
if whenReferenced >= maxReplace:
# print 'OPT: ??? updating maxReplace (%d %d %d)' % (replaceIdx, replacePage, maxReplace)
replaceIdx = pageIndex
replacePage = page
maxReplace = whenReferenced
# print 'OPT: --> updating maxReplace (%d %d %d)' % (replaceIdx, replacePage, maxReplace)
victim = memory.pop(replaceIdx)
# print 'OPT: replacing page %d (idx:%d) because I saw it in future at %d' % (victim, replaceIdx, whenReferenced)
elif policy == 'UNOPT':
minReplace = len(addrList) + 1
replaceIdx = -1
replacePage = -1
for pageIndex in range(0,count):
page = memory[pageIndex]
# now, have page 'page' at index 'pageIndex' in memory
whenReferenced = len(addrList)
# whenReferenced tells us when, in the future, this was referenced
for futureIdx in range(addrIndex+1,len(addrList)):
futurePage = int(addrList[futureIdx])
if page == futurePage:
whenReferenced = futureIdx
break
if whenReferenced < minReplace:
replaceIdx = pageIndex
replacePage = page
minReplace = whenReferenced
victim = memory.pop(replaceIdx)
else:
# miss, but no replacement needed (cache not full)
victim = -1
count = count + 1
# now add to memory
memory.append(n)
if cdebug:
print 'LEN (a)', len(memory)
if victim != -1:
assert(victim not in memory)
# after miss processing, update reference bit
if n not in ref:
ref[n] = 1
else:
ref[n] += 1
if ref[n] > clockbits:
ref[n] = clockbits
if cdebug:
print 'REF (a)', ref
if notrace == False:
print 'Access: %d %s %s -> %12s <- %s Replaced:%s [Hits:%d Misses:%d]' % (n, hfunc(idx), leftStr, memory, riteStr, vfunc(victim), hits, miss)
addrIndex = addrIndex + 1
print ''
print 'FINALSTATS hits %d misses %d hitrate %.2f' % (hits, miss, (100.0*float(hits))/(float(hits)+float(miss)))
print ''